MediaProvider.java revision 10af34f31704509a71d02b0b4a15cfa07bbfede3
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; 33ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwoodimport android.content.SharedPreferences; 34bdd3b8337b01920822c128b1ad1be202e22d070cOwen Linimport android.content.UriMatcher; 3570676508bd3a081edd909875e141f2c48d79c1acDaniel Lehmannimport android.content.res.Resources; 36702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.database.Cursor; 37ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissenimport android.database.DatabaseUtils; 380027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissenimport android.database.MatrixCursor; 39702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.database.sqlite.SQLiteDatabase; 40702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.database.sqlite.SQLiteOpenHelper; 41702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.database.sqlite.SQLiteQueryBuilder; 42702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.graphics.Bitmap; 43702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.graphics.BitmapFactory; 44b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwoodimport android.media.MediaFile; 45702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.media.MediaScanner; 46b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chenimport android.media.MiniThumbFile; 4790345783ad297da6059398cab174687de6f36a5bMike Lockwoodimport android.mtp.MtpConstants; 489be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwoodimport android.mtp.MtpStorage; 49702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.net.Uri; 50702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.Binder; 51702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.Environment; 52702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.FileUtils; 53702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.Handler; 54ab43e1853533e4d9352c251d53c36fb645077e43Chih-Chung Changimport android.os.HandlerThread; 55702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.Message; 56702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.ParcelFileDescriptor; 57702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.Process; 58d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwoodimport android.os.RemoteException; 5910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissenimport android.os.SystemClock; 604f2186758ee1c6eaa702bf1511b233b26143b631Mike Lockwoodimport android.os.SystemProperties; 61c47e4f2921312098eddc5fe49b080e0f2df60e81Mike Lockwoodimport android.os.storage.StorageManager; 621f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwoodimport android.os.storage.StorageVolume; 63ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwoodimport android.preference.PreferenceManager; 64702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.BaseColumns; 65702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.MediaStore; 66702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.MediaStore.Audio; 675bf5c26a3499d584332074baab97392696ed9614Ray Chenimport android.provider.MediaStore.Files; 6870676508bd3a081edd909875e141f2c48d79c1acDaniel Lehmannimport android.provider.MediaStore.Files.FileColumns; 69702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.MediaStore.Images; 7070676508bd3a081edd909875e141f2c48d79c1acDaniel Lehmannimport android.provider.MediaStore.Images.ImageColumns; 71702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.MediaStore.MediaColumns; 72702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.MediaStore.Video; 73702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.text.TextUtils; 7410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissenimport android.text.format.DateUtils; 75702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.util.Log; 76702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 77702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.io.File; 7810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissenimport java.io.FileDescriptor; 79702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.io.FileInputStream; 80702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.io.FileNotFoundException; 81702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.io.IOException; 82702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.io.OutputStream; 8310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissenimport java.io.PrintWriter; 84702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.text.Collator; 85cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissenimport java.util.ArrayList; 8610af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissenimport java.util.Collection; 87702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.util.HashMap; 88702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.util.HashSet; 89702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.util.Iterator; 90f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissenimport java.util.List; 91b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chenimport java.util.PriorityQueue; 928a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huberimport java.util.Stack; 93702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 94702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project/** 95702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Media content provider. See {@link android.provider.MediaStore} for details. 96702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Separate databases are kept for each external storage card we see (using the 97702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * card's ID as an index). The content visible at content://media/external/... 98702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * changes with the card. 99702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 100702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectpublic class MediaProvider extends ContentProvider { 101702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final Uri MEDIA_URI = Uri.parse("content://media"); 102702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final Uri ALBUMART_URI = Uri.parse("content://media/external/audio/albumart"); 103b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private static final int ALBUM_THUMB = 1; 104b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private static final int IMAGE_THUMB = 2; 105702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 106702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final HashMap<String, String> sArtistAlbumsMap = new HashMap<String, String>(); 107d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen private static final HashMap<String, String> sFolderArtMap = new HashMap<String, String>(); 108702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1097f36494e085c26c69cd5925e54028822025eff29Marco Nelissen // In memory cache of path<->id mappings, to speed up inserts during media scan 1107f36494e085c26c69cd5925e54028822025eff29Marco Nelissen HashMap<String, Long> mDirectoryCache = new HashMap<String, Long>(); 1117f36494e085c26c69cd5925e54028822025eff29Marco Nelissen 1128a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // A HashSet of paths that are pending creation of album art thumbnails. 1138a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber private HashSet mPendingThumbs = new HashSet(); 1148a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 1158a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // A Stack of outstanding thumbnail requests. 1168a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber private Stack mThumbRequestStack = new Stack(); 1178a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 11820434e032e498b716f87cce2f23dd646819218bfRay Chen // The lock of mMediaThumbQueue protects both mMediaThumbQueue and mCurrentThumbRequest. 11920434e032e498b716f87cce2f23dd646819218bfRay Chen private MediaThumbRequest mCurrentThumbRequest = null; 120b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private PriorityQueue<MediaThumbRequest> mMediaThumbQueue = 121b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen new PriorityQueue<MediaThumbRequest>(MediaThumbRequest.PRIORITY_NORMAL, 122b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen MediaThumbRequest.getComparator()); 123b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 124f7cc647081f0421c0247de275fa0754b29938c07Mike Lockwood private boolean mCaseInsensitivePaths; 1259be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood private static String[] mExternalStoragePaths; 12617ad80b32f839ccddac3911799ff732d1ca3a006Mike Lockwood 127a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // For compatibility with the approximately 0 apps that used mediaprovider search in 128a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // releases 1.0, 1.1 or 1.5 129a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen private String[] mSearchColsLegacy = new String[] { 130a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen android.provider.BaseColumns._ID, 131a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen MediaStore.Audio.Media.MIME_TYPE, 132a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "(CASE WHEN grouporder=1 THEN " + R.drawable.ic_search_category_music_artist + 133a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen " ELSE CASE WHEN grouporder=2 THEN " + R.drawable.ic_search_category_music_album + 134a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen " ELSE " + R.drawable.ic_search_category_music_song + " END END" + 135a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen ") AS " + SearchManager.SUGGEST_COLUMN_ICON_1, 136a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "0 AS " + SearchManager.SUGGEST_COLUMN_ICON_2, 137a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "text1 AS " + SearchManager.SUGGEST_COLUMN_TEXT_1, 138a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "text1 AS " + SearchManager.SUGGEST_COLUMN_QUERY, 139a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "CASE when grouporder=1 THEN data1 ELSE artist END AS data1", 140a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "CASE when grouporder=1 THEN data2 ELSE " + 141a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "CASE WHEN grouporder=2 THEN NULL ELSE album END END AS data2", 142a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "match as ar", 143a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen SearchManager.SUGGEST_COLUMN_INTENT_DATA, 144a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "grouporder", 145ea74c8add2d5b4215dfeb69183632d9e9797ac5aMarco Nelissen "NULL AS itemorder" // We should be sorting by the artist/album/title keys, but that 146ea74c8add2d5b4215dfeb69183632d9e9797ac5aMarco Nelissen // column is not available here, and the list is already sorted. 147a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen }; 148a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen private String[] mSearchColsFancy = new String[] { 149a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen android.provider.BaseColumns._ID, 150a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen MediaStore.Audio.Media.MIME_TYPE, 151a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen MediaStore.Audio.Artists.ARTIST, 152a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen MediaStore.Audio.Albums.ALBUM, 153a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen MediaStore.Audio.Media.TITLE, 154a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "data1", 155a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "data2", 156a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen }; 15763f748ff8b258d9110038778a006b3000164fbeeSatish Sampath // If this array gets changed, please update the constant below to point to the correct item. 158a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen private String[] mSearchColsBasic = new String[] { 159a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen android.provider.BaseColumns._ID, 160a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen MediaStore.Audio.Media.MIME_TYPE, 161a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "(CASE WHEN grouporder=1 THEN " + R.drawable.ic_search_category_music_artist + 162a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen " ELSE CASE WHEN grouporder=2 THEN " + R.drawable.ic_search_category_music_album + 163a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen " ELSE " + R.drawable.ic_search_category_music_song + " END END" + 164a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen ") AS " + SearchManager.SUGGEST_COLUMN_ICON_1, 165a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "text1 AS " + SearchManager.SUGGEST_COLUMN_TEXT_1, 166a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "text1 AS " + SearchManager.SUGGEST_COLUMN_QUERY, 16763f748ff8b258d9110038778a006b3000164fbeeSatish Sampath "(CASE WHEN grouporder=1 THEN '%1'" + // %1 gets replaced with localized string. 16863f748ff8b258d9110038778a006b3000164fbeeSatish Sampath " ELSE CASE WHEN grouporder=3 THEN artist || ' - ' || album" + 169e31cfb1a2c21e7ac7a646d40afbb48f49fab6907Marco Nelissen " ELSE CASE WHEN text2!='" + MediaStore.UNKNOWN_STRING + "' THEN text2" + 17063f748ff8b258d9110038778a006b3000164fbeeSatish Sampath " ELSE NULL END END END) AS " + SearchManager.SUGGEST_COLUMN_TEXT_2, 171a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen SearchManager.SUGGEST_COLUMN_INTENT_DATA 172a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen }; 17363f748ff8b258d9110038778a006b3000164fbeeSatish Sampath // Position of the TEXT_2 item in the above array. 17463f748ff8b258d9110038778a006b3000164fbeeSatish Sampath private final int SEARCH_COLUMN_BASIC_TEXT2 = 5; 175a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen 1761717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood private static final String[] mMediaTableColumns = new String[] { 17716dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood FileColumns._ID, 178afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood FileColumns.MEDIA_TYPE, 1791717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood }; 1801717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood 1817f36494e085c26c69cd5925e54028822025eff29Marco Nelissen private static final String[] sIdOnlyColumn = new String[] { 1827f36494e085c26c69cd5925e54028822025eff29Marco Nelissen FileColumns._ID 1837f36494e085c26c69cd5925e54028822025eff29Marco Nelissen }; 1847f36494e085c26c69cd5925e54028822025eff29Marco Nelissen 185a9c4e330dacb37cfffa9c00f7da83cafde4accefMarco Nelissen private Uri mAlbumArtBaseUri = Uri.parse("content://media/external/audio/albumart"); 186a9c4e330dacb37cfffa9c00f7da83cafde4accefMarco Nelissen 187702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private BroadcastReceiver mUnmountReceiver = new BroadcastReceiver() { 188702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 189702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public void onReceive(Context context, Intent intent) { 190702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (intent.getAction().equals(Intent.ACTION_MEDIA_EJECT)) { 1911f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood StorageVolume storage = (StorageVolume)intent.getParcelableExtra( 1921f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood StorageVolume.EXTRA_STORAGE_VOLUME); 1931f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood // If primary external storage is ejected, then remove the external volume 1941f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood // notify all cursors backed by data on that volume. 1951f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood if (storage.getPath().equals(mExternalStoragePaths[0])) { 1961f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood detachVolume(Uri.parse("content://media/external")); 1971f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood sFolderArtMap.clear(); 1981f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood MiniThumbFile.reset(); 1991f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood } else { 2001f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood // If secondary external storage is ejected, then we delete all database 2011f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood // entries for that storage from the files table. 2021f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood synchronized (mDatabases) { 2031f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood DatabaseHelper database = mDatabases.get(EXTERNAL_VOLUME); 2041f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood Uri uri = Uri.parse("file://" + storage.getPath()); 2051f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood if (database != null) { 2061f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood try { 2071f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood // Send media scanner started and stopped broadcasts for apps that rely 2081f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood // on these Intents for coarse grained media database notifications. 2091f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood context.sendBroadcast( 2101f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood new Intent(Intent.ACTION_MEDIA_SCANNER_STARTED, uri)); 2111f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood 2121f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood // don't send objectRemoved events - MTP be sending StorageRemoved anyway 2131f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood mDisableMtpObjectCallbacks = true; 2141f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood Log.d(TAG, "deleting all entries for storage " + storage); 2151f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood SQLiteDatabase db = database.getWritableDatabase(); 2164b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood // First clear the file path to disable the _DELETE_FILE database hook. 2174b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood // We do this to avoid deleting files if the volume is remounted while 2184b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood // we are still processing the unmount event. 2194b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood ContentValues values = new ContentValues(); 2204b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood values.put(Files.FileColumns.DATA, ""); 2214b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood String where = FileColumns.STORAGE_ID + "=?"; 2224b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood String[] whereArgs = new String[] { Integer.toString(storage.getStorageId()) }; 2234b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood db.update("files", values, where, whereArgs); 2244b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood // now delete the records 2254b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood db.delete("files", where, whereArgs); 2264b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood // notify on media Uris as well as the files Uri 2274b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood context.getContentResolver().notifyChange( 2284b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood Audio.Media.getContentUri(EXTERNAL_VOLUME), null); 2294b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood context.getContentResolver().notifyChange( 2304b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood Images.Media.getContentUri(EXTERNAL_VOLUME), null); 2314b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood context.getContentResolver().notifyChange( 2324b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood Video.Media.getContentUri(EXTERNAL_VOLUME), null); 2331f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood context.getContentResolver().notifyChange( 2341f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood Files.getContentUri(EXTERNAL_VOLUME), null); 2351f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood } catch (Exception e) { 2361f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood Log.e(TAG, "exception deleting storage entries", e); 2371f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood } finally { 2381f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood context.sendBroadcast( 2391f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood new Intent(Intent.ACTION_MEDIA_SCANNER_FINISHED, uri)); 2401f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood mDisableMtpObjectCallbacks = false; 2411f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood } 2421f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood } 2431f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood } 2441f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood } 245702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 246702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 247702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project }; 248702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 249d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood // set to disable sending events when the operation originates from MTP 250d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood private boolean mDisableMtpObjectCallbacks; 251d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 252d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood private final SQLiteDatabase.CustomFunction mObjectRemovedCallback = 253d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood new SQLiteDatabase.CustomFunction() { 254d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood public void callback(String[] args) { 2557f36494e085c26c69cd5925e54028822025eff29Marco Nelissen // We could remove only the deleted entry from the cache, but that 2567f36494e085c26c69cd5925e54028822025eff29Marco Nelissen // requires the path, which we don't have here, so instead we just 2577f36494e085c26c69cd5925e54028822025eff29Marco Nelissen // clear the entire cache. 2587f36494e085c26c69cd5925e54028822025eff29Marco Nelissen // TODO: include the path in the callback and only remove the affected 2597f36494e085c26c69cd5925e54028822025eff29Marco Nelissen // entry from the cache 2607f36494e085c26c69cd5925e54028822025eff29Marco Nelissen mDirectoryCache.clear(); 261d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood // do nothing if the operation originated from MTP 262d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood if (mDisableMtpObjectCallbacks) return; 263d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 264d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood Log.d(TAG, "object removed " + args[0]); 265d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood IMtpService mtpService = mMtpService; 266d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood if (mtpService != null) { 267d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood try { 268d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood sendObjectRemoved(Integer.parseInt(args[0])); 269d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } catch (NumberFormatException e) { 270d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood Log.e(TAG, "NumberFormatException in mObjectRemovedCallback", e); 271d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 272d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 273d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 274d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood }; 275d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 276702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 277702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Wrapper class for a specific database (associated with one particular 278702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * external card, or with internal storage). Can open the actual database 279702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * on demand, create and upgrade the schema, etc. 280702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 281fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn static final class DatabaseHelper extends SQLiteOpenHelper { 282702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final Context mContext; 2835524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood final String mName; 284702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final boolean mInternal; // True if this is the internal database 285fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn final boolean mEarlyUpgrade; 286fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn final SQLiteDatabase.CustomFunction mObjectRemovedCallback; 2875524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood boolean mUpgradeAttempted; // Used for upgrade error handling 28810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen int mNumQueries; 28910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen int mNumUpdates; 29010af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen int mNumInserts; 29110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen int mNumDeletes; 29210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen long mScanStartTime; 29310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen long mScanStopTime; 294702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 295702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // In memory caches of artist and album data. 296702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project HashMap<String, Long> mArtistCache = new HashMap<String, Long>(); 297702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project HashMap<String, Long> mAlbumCache = new HashMap<String, Long>(); 298702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 299fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn public DatabaseHelper(Context context, String name, boolean internal, 300fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn boolean earlyUpgrade, 301fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn SQLiteDatabase.CustomFunction objectRemovedCallback) { 302702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project super(context, name, null, DATABASE_VERSION); 303702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mContext = context; 3045524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood mName = name; 305702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mInternal = internal; 306fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn mEarlyUpgrade = earlyUpgrade; 307fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn mObjectRemovedCallback = objectRemovedCallback; 308702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 309702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 310702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 311702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Creates database the first time we try to open it. 312702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 313702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 314702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public void onCreate(final SQLiteDatabase db) { 315702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project updateDatabase(db, mInternal, 0, DATABASE_VERSION); 316702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 317702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 318702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 319702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Updates the database format when a new content provider is used 320702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * with an older database format. 321702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 322702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 323702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public void onUpgrade(final SQLiteDatabase db, final int oldV, final int newV) { 3245524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood mUpgradeAttempted = true; 325702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project updateDatabase(db, mInternal, oldV, newV); 326702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 327702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 328db8357b2b2888ce3778278e9cd9e698347ca6105Owen Lin @Override 329db8357b2b2888ce3778278e9cd9e698347ca6105Owen Lin public synchronized SQLiteDatabase getWritableDatabase() { 3305524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood SQLiteDatabase result = null; 3315524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood mUpgradeAttempted = false; 3325524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood try { 3335524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood result = super.getWritableDatabase(); 3345524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood } catch (Exception e) { 3355524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood if (!mUpgradeAttempted) { 3365524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood Log.e(TAG, "failed to open database " + mName, e); 3375524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood return null; 3385524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood } 3395524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood } 3405524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood 3415524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood // If we failed to open the database during an upgrade, delete the file and try again. 3425524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood // This will result in the creation of a fresh database, which will be repopulated 3435524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood // when the media scanner runs. 3445524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood if (result == null && mUpgradeAttempted) { 3455524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood mContext.getDatabasePath(mName).delete(); 3465524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood result = super.getWritableDatabase(); 3475524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood } 3485524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood return result; 3495524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood } 3505524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood 351702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 352993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood * For devices that have removable storage, we support keeping multiple databases 353993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood * to allow users to switch between a number of cards. 354993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood * On such devices, touch this particular database and garbage collect old databases. 355702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * An LRU cache system is used to clean up databases for old external 356702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * storage volumes. 357702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 358702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 359702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public void onOpen(SQLiteDatabase db) { 36036d7136bebac6ea5738fb653a74dcd6c71e4cd58Dmitry Dolinsky 361652c337bac290c7dfcde8725e7c771193a7f7ed6Vasu Nori // Turn on WAL optimization 362652c337bac290c7dfcde8725e7c771193a7f7ed6Vasu Nori db.enableWriteAheadLogging(); 36336d7136bebac6ea5738fb653a74dcd6c71e4cd58Dmitry Dolinsky 364702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (mInternal) return; // The internal database is kept separately. 365702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 366fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn if (mEarlyUpgrade) return; // Doing early upgrade. 367fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn 368fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn if (mObjectRemovedCallback != null) { 369fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn db.addCustomFunction("_OBJECT_REMOVED", 1, mObjectRemovedCallback); 370fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn } 371d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 372993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood // the code below is only needed on devices with removable storage 373993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood if (!Environment.isExternalStorageRemovable()) return; 374993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood 375702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // touch the database file to show it is most recently used 376702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File file = new File(db.getPath()); 377702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long now = System.currentTimeMillis(); 378702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project file.setLastModified(now); 379702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 380702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // delete least recently used databases if we are over the limit 381702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String[] databases = mContext.databaseList(); 382702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int count = databases.length; 383702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int limit = MAX_EXTERNAL_DATABASES; 384702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 385702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // delete external databases that have not been used in the past two months 386702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long twoMonthsAgo = now - OBSOLETE_DATABASE_DB; 387702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project for (int i = 0; i < databases.length; i++) { 388702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File other = mContext.getDatabasePath(databases[i]); 389702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (INTERNAL_DATABASE_NAME.equals(databases[i]) || file.equals(other)) { 390702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project databases[i] = null; 391702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count--; 392702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (file.equals(other)) { 393702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // reduce limit to account for the existence of the database we 394702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // are about to open, which we removed from the list. 395702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project limit--; 396702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 397702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 398702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long time = other.lastModified(); 399702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (time < twoMonthsAgo) { 400702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (LOCAL_LOGV) Log.v(TAG, "Deleting old database " + databases[i]); 401702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mContext.deleteDatabase(databases[i]); 402702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project databases[i] = null; 403702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count--; 404702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 405702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 406702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 407702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 408702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // delete least recently used databases until 409702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // we are no longer over the limit 410702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project while (count > limit) { 411702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int lruIndex = -1; 412702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long lruTime = 0; 413702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 414702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project for (int i = 0; i < databases.length; i++) { 415702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (databases[i] != null) { 416702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long time = mContext.getDatabasePath(databases[i]).lastModified(); 417702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (lruTime == 0 || time < lruTime) { 418702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project lruIndex = i; 419702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project lruTime = time; 420702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 421702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 422702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 423702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 424702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // delete least recently used database 425702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (lruIndex != -1) { 426702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (LOCAL_LOGV) Log.v(TAG, "Deleting old database " + databases[lruIndex]); 427702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mContext.deleteDatabase(databases[lruIndex]); 428702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project databases[lruIndex] = null; 429702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count--; 430702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 431702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 432702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 433702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 434702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 43534be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood // synchronize on mMtpServiceConnection when accessing mMtpService 436d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood private IMtpService mMtpService; 437d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 438d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood private final ServiceConnection mMtpServiceConnection = new ServiceConnection() { 439d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood public void onServiceConnected(ComponentName className, android.os.IBinder service) { 44034be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood synchronized (this) { 44134be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood mMtpService = IMtpService.Stub.asInterface(service); 44234be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood } 443d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 444d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 445d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood public void onServiceDisconnected(ComponentName className) { 44634be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood synchronized (this) { 44734be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood mMtpService = null; 44834be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood } 449d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 450d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood }; 451d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 452ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood private static final String[] sDefaultFolderNames = { 453ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood Environment.DIRECTORY_MUSIC, 454ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood Environment.DIRECTORY_PODCASTS, 455ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood Environment.DIRECTORY_RINGTONES, 456ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood Environment.DIRECTORY_ALARMS, 457ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood Environment.DIRECTORY_NOTIFICATIONS, 458ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood Environment.DIRECTORY_PICTURES, 459ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood Environment.DIRECTORY_MOVIES, 460ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood Environment.DIRECTORY_DOWNLOADS, 461ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood Environment.DIRECTORY_DCIM, 462ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood }; 463ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood 464ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood // creates default folders (Music, Downloads, etc) 46510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen private void createDefaultFolders(DatabaseHelper helper, SQLiteDatabase db) { 466ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood // Use a SharedPreference to ensure we only do this once. 467ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood // We don't want to annoy the user by recreating the directories 468ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood // after she has deleted them. 469ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext()); 470ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood if (prefs.getInt("created_default_folders", 0) == 0) { 471ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood for (String folderName : sDefaultFolderNames) { 472ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood File file = Environment.getExternalStoragePublicDirectory(folderName); 473ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood if (!file.exists()) { 474ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood file.mkdirs(); 47510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen insertDirectory(helper, db, file.getAbsolutePath()); 476ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood } 477ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood } 478ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood 479ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood SharedPreferences.Editor e = prefs.edit(); 480ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood e.clear(); 481ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood e.putInt("created_default_folders", 1); 482ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood e.commit(); 483ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood } 484ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood } 485ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood 486702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 487702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public boolean onCreate() { 488d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood final Context context = getContext(); 489d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 490acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen sArtistAlbumsMap.put(MediaStore.Audio.Albums._ID, "audio.album_id AS " + 491acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen MediaStore.Audio.Albums._ID); 492702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Albums.ALBUM, "album"); 493702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Albums.ALBUM_KEY, "album_key"); 494acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen sArtistAlbumsMap.put(MediaStore.Audio.Albums.FIRST_YEAR, "MIN(year) AS " + 495702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.Audio.Albums.FIRST_YEAR); 496acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen sArtistAlbumsMap.put(MediaStore.Audio.Albums.LAST_YEAR, "MAX(year) AS " + 497702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.Audio.Albums.LAST_YEAR); 498702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Media.ARTIST, "artist"); 499702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Media.ARTIST_ID, "artist"); 500702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Media.ARTIST_KEY, "artist_key"); 501acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen sArtistAlbumsMap.put(MediaStore.Audio.Albums.NUMBER_OF_SONGS, "count(*) AS " + 502acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen MediaStore.Audio.Albums.NUMBER_OF_SONGS); 503acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen sArtistAlbumsMap.put(MediaStore.Audio.Albums.ALBUM_ART, "album_art._data AS " + 504acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen MediaStore.Audio.Albums.ALBUM_ART); 505702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 50663f748ff8b258d9110038778a006b3000164fbeeSatish Sampath mSearchColsBasic[SEARCH_COLUMN_BASIC_TEXT2] = 50763f748ff8b258d9110038778a006b3000164fbeeSatish Sampath mSearchColsBasic[SEARCH_COLUMN_BASIC_TEXT2].replaceAll( 508d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood "%1", context.getString(R.string.artist_label)); 509702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mDatabases = new HashMap<String, DatabaseHelper>(); 510702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project attachVolume(INTERNAL_VOLUME); 511702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 512702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project IntentFilter iFilter = new IntentFilter(Intent.ACTION_MEDIA_EJECT); 513702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project iFilter.addDataScheme("file"); 514d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood context.registerReceiver(mUnmountReceiver, iFilter); 515702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 5167d4f72d8ab71e28e9d40da87ec8c75ded254dd08Dianne Hackborn mCaseInsensitivePaths = true; 5174f2186758ee1c6eaa702bf1511b233b26143b631Mike Lockwood 518c47e4f2921312098eddc5fe49b080e0f2df60e81Mike Lockwood StorageManager storageManager = 519c47e4f2921312098eddc5fe49b080e0f2df60e81Mike Lockwood (StorageManager)context.getSystemService(Context.STORAGE_SERVICE); 520c47e4f2921312098eddc5fe49b080e0f2df60e81Mike Lockwood mExternalStoragePaths = storageManager.getVolumePaths(); 5219be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood 522702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // open external database if external storage is mounted 523702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String state = Environment.getExternalStorageState(); 524702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (Environment.MEDIA_MOUNTED.equals(state) || 525702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) { 526702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project attachVolume(EXTERNAL_VOLUME); 527702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 528702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 529ab43e1853533e4d9352c251d53c36fb645077e43Chih-Chung Chang HandlerThread ht = new HandlerThread("thumbs thread", Process.THREAD_PRIORITY_BACKGROUND); 530ab43e1853533e4d9352c251d53c36fb645077e43Chih-Chung Chang ht.start(); 531ab43e1853533e4d9352c251d53c36fb645077e43Chih-Chung Chang mThumbHandler = new Handler(ht.getLooper()) { 532702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 533702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public void handleMessage(Message msg) { 534b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (msg.what == IMAGE_THUMB) { 535b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen synchronized (mMediaThumbQueue) { 53620434e032e498b716f87cce2f23dd646819218bfRay Chen mCurrentThumbRequest = mMediaThumbQueue.poll(); 537b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 53820434e032e498b716f87cce2f23dd646819218bfRay Chen if (mCurrentThumbRequest == null) { 539b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen Log.w(TAG, "Have message but no request?"); 540b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } else { 541b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen try { 54220434e032e498b716f87cce2f23dd646819218bfRay Chen File origFile = new File(mCurrentThumbRequest.mPath); 5434d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen if (origFile.exists() && origFile.length() > 0) { 54420434e032e498b716f87cce2f23dd646819218bfRay Chen mCurrentThumbRequest.execute(); 5454d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen } else { 5464d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen // original file hasn't been stored yet 5474d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen synchronized (mMediaThumbQueue) { 54820434e032e498b716f87cce2f23dd646819218bfRay Chen Log.w(TAG, "original file hasn't been stored yet: " + mCurrentThumbRequest.mPath); 5494d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen } 5504d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen } 551b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } catch (IOException ex) { 5521d6eba9e1e28c722aa73a651d86a2efe2b937bf2Ray Chen Log.w(TAG, ex); 5531d6eba9e1e28c722aa73a651d86a2efe2b937bf2Ray Chen } catch (UnsupportedOperationException ex) { 5541d6eba9e1e28c722aa73a651d86a2efe2b937bf2Ray Chen // This could happen if we unplug the sd card during insert/update/delete 5551d6eba9e1e28c722aa73a651d86a2efe2b937bf2Ray Chen // See getDatabaseForUri. 5561d6eba9e1e28c722aa73a651d86a2efe2b937bf2Ray Chen Log.w(TAG, ex); 55722c5095b70a9fd6304fcf2366e8e40e37ae95764Erik Rydgren } catch (OutOfMemoryError err) { 55822c5095b70a9fd6304fcf2366e8e40e37ae95764Erik Rydgren /* 55922c5095b70a9fd6304fcf2366e8e40e37ae95764Erik Rydgren * Note: Catching Errors is in most cases considered 56022c5095b70a9fd6304fcf2366e8e40e37ae95764Erik Rydgren * bad practice. However, in this case it is 56122c5095b70a9fd6304fcf2366e8e40e37ae95764Erik Rydgren * motivated by the fact that corrupt or very large 56222c5095b70a9fd6304fcf2366e8e40e37ae95764Erik Rydgren * images may cause a huge allocation to be 56322c5095b70a9fd6304fcf2366e8e40e37ae95764Erik Rydgren * requested and denied. The bitmap handling API in 56422c5095b70a9fd6304fcf2366e8e40e37ae95764Erik Rydgren * Android offers no other way to guard against 56522c5095b70a9fd6304fcf2366e8e40e37ae95764Erik Rydgren * these problems than by catching OutOfMemoryError. 56622c5095b70a9fd6304fcf2366e8e40e37ae95764Erik Rydgren */ 56722c5095b70a9fd6304fcf2366e8e40e37ae95764Erik Rydgren Log.w(TAG, err); 568b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } finally { 56920434e032e498b716f87cce2f23dd646819218bfRay Chen synchronized (mCurrentThumbRequest) { 57020434e032e498b716f87cce2f23dd646819218bfRay Chen mCurrentThumbRequest.mState = MediaThumbRequest.State.DONE; 57120434e032e498b716f87cce2f23dd646819218bfRay Chen mCurrentThumbRequest.notifyAll(); 572b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 573b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 574b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 575b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } else if (msg.what == ALBUM_THUMB) { 576b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen ThumbData d; 577b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen synchronized (mThumbRequestStack) { 578b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen d = (ThumbData)mThumbRequestStack.pop(); 579b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 5808a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 581b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen makeThumbInternal(d); 582b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen synchronized (mPendingThumbs) { 583b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen mPendingThumbs.remove(d.path); 584b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 5858a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 586702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 587702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project }; 588702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 589702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return true; 590702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 591702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 592afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood private static final String IMAGE_COLUMNS = 593afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "_data,_size,_display_name,mime_type,title,date_added," + 594afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "date_modified,description,picasa_id,isprivate,latitude,longitude," + 595bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang "datetaken,orientation,mini_thumb_magic,bucket_id,bucket_display_name," + 596bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang "width,height"; 597bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang 598bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang private static final String IMAGE_COLUMNSv407 = 599bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang "_data,_size,_display_name,mime_type,title,date_added," + 600bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang "date_modified,description,picasa_id,isprivate,latitude,longitude," + 601afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "datetaken,orientation,mini_thumb_magic,bucket_id,bucket_display_name"; 602afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 603805b0b734dd5a73e2f77cd8d818a07a8627a8c1eMarco Nelissen private static final String AUDIO_COLUMNSv99 = 604afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "_data,_display_name,_size,mime_type,date_added," + 605afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "date_modified,title,title_key,duration,artist_id,composer,album_id," + 606afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "track,year,is_ringtone,is_music,is_alarm,is_notification,is_podcast," + 607afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "bookmark"; 608afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 609805b0b734dd5a73e2f77cd8d818a07a8627a8c1eMarco Nelissen private static final String AUDIO_COLUMNSv100 = 610805b0b734dd5a73e2f77cd8d818a07a8627a8c1eMarco Nelissen "_data,_display_name,_size,mime_type,date_added," + 611805b0b734dd5a73e2f77cd8d818a07a8627a8c1eMarco Nelissen "date_modified,title,title_key,duration,artist_id,composer,album_id," + 612805b0b734dd5a73e2f77cd8d818a07a8627a8c1eMarco Nelissen "track,year,is_ringtone,is_music,is_alarm,is_notification,is_podcast," + 613805b0b734dd5a73e2f77cd8d818a07a8627a8c1eMarco Nelissen "bookmark,album_artist"; 614805b0b734dd5a73e2f77cd8d818a07a8627a8c1eMarco Nelissen 615957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang private static final String AUDIO_COLUMNSv405 = 616957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang "_data,_display_name,_size,mime_type,date_added,is_drm," + 617957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang "date_modified,title,title_key,duration,artist_id,composer,album_id," + 618957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang "track,year,is_ringtone,is_music,is_alarm,is_notification,is_podcast," + 619957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang "bookmark,album_artist"; 620957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang 621afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood private static final String VIDEO_COLUMNS = 622afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "_data,_display_name,_size,mime_type,date_added,date_modified," + 623afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "title,duration,artist,album,resolution,description,isprivate,tags," + 624afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "category,language,mini_thumb_data,latitude,longitude,datetaken," + 625bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang "mini_thumb_magic,bucket_id,bucket_display_name,bookmark,width," + 626bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang "height"; 627bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang 628bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang private static final String VIDEO_COLUMNSv407 = 629bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang "_data,_display_name,_size,mime_type,date_added,date_modified," + 630bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang "title,duration,artist,album,resolution,description,isprivate,tags," + 631bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang "category,language,mini_thumb_data,latitude,longitude,datetaken," + 632afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "mini_thumb_magic,bucket_id,bucket_display_name, bookmark"; 633afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 634afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood private static final String PLAYLIST_COLUMNS = "_data,name,date_added,date_modified"; 635afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 636702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 637702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * This method takes care of updating all the tables in the database to the 638702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * current version, creating them if necessary. 639702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * This method can only update databases at schema 63 or higher, which was 640702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * created August 1, 2008. Older database will be cleared and recreated. 641702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param db Database 642702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param internal True if this is the internal media database 643702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 644702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static void updateDatabase(SQLiteDatabase db, boolean internal, 645702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int fromVersion, int toVersion) { 646702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 647702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // sanity checks 648702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (toVersion != DATABASE_VERSION) { 649702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Log.e(TAG, "Illegal update request. Got " + toVersion + ", expected " + 650702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DATABASE_VERSION); 651702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalArgumentException(); 652702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else if (fromVersion > toVersion) { 65395ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen Log.e(TAG, "Illegal update request: can't downgrade from " + fromVersion + 654702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " to " + toVersion + ". Did you forget to wipe data?"); 655702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalArgumentException(); 656702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 657702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 658d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood // Revisions 84-86 were a failed attempt at supporting the "album artist" id3 tag. 659acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // We can't downgrade from those revisions, so start over. 660022eb71bfe8ec65b8817eaa432a530194210ec23Marco Nelissen // (the initial change to do this was wrong, so now we actually need to start over 661022eb71bfe8ec65b8817eaa432a530194210ec23Marco Nelissen // if the database version is 84-89) 662bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin // Post-gingerbread, revisions 91-94 were broken in a way that is not easy to repair. 663bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin // However version 91 was reused in a divergent development path for gingerbread, 664bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin // so we need to support upgrades from 91. 665bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin // Therefore we will only force a reset for versions 92 - 94. 666d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood if (fromVersion < 63 || (fromVersion >= 84 && fromVersion <= 89) || 667bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin (fromVersion >= 92 && fromVersion <= 94)) { 668702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Drop everything and start over. 669702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Log.i(TAG, "Upgrading media database from version " + 670702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project fromVersion + " to " + toVersion + ", which will destroy all old data"); 671d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen fromVersion = 63; 672702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS images"); 673702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS images_cleanup"); 674702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS thumbnails"); 675702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS thumbnails_cleanup"); 676702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS audio_meta"); 677702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS artists"); 678702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS albums"); 679702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS album_art"); 680702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP VIEW IF EXISTS artist_info"); 681702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP VIEW IF EXISTS album_info"); 682702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP VIEW IF EXISTS artists_albums_map"); 683702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS audio_meta_cleanup"); 684702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS audio_genres"); 685702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS audio_genres_map"); 686702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS audio_genres_cleanup"); 687702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS audio_playlists"); 688702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS audio_playlists_map"); 689702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS audio_playlists_cleanup"); 690702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS albumart_cleanup1"); 691702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS albumart_cleanup2"); 692702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS video"); 693702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS video_cleanup"); 694cec8df8a90209fc4df5d1ff5f02dc364d0d2edc6Mike Lockwood db.execSQL("DROP TABLE IF EXISTS objects"); 6959ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood db.execSQL("DROP TRIGGER IF EXISTS images_objects_cleanup"); 6969ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood db.execSQL("DROP TRIGGER IF EXISTS audio_objects_cleanup"); 6979ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood db.execSQL("DROP TRIGGER IF EXISTS video_objects_cleanup"); 6989ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood db.execSQL("DROP TRIGGER IF EXISTS playlists_objects_cleanup"); 699702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 700702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS images (" + 701702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 702702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_data TEXT," + 703702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_size INTEGER," + 704702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_display_name TEXT," + 705702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "mime_type TEXT," + 706702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "title TEXT," + 707702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_added INTEGER," + 708702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_modified INTEGER," + 709702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "description TEXT," + 710702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "picasa_id TEXT," + 711702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "isprivate INTEGER," + 712702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "latitude DOUBLE," + 713702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "longitude DOUBLE," + 714702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "datetaken INTEGER," + 715702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "orientation INTEGER," + 716702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "mini_thumb_magic INTEGER," + 717702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "bucket_id TEXT," + 718702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "bucket_display_name TEXT" + 719702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 720702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 721702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE INDEX IF NOT EXISTS mini_thumb_magic_index on images(mini_thumb_magic);"); 722702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 723702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS images_cleanup DELETE ON images " + 724702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 725702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE FROM thumbnails WHERE image_id = old._id;" + 726702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT _DELETE_FILE(old._data);" + 727702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 728702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 729b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // create image thumbnail table 730702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS thumbnails (" + 731702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 732702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_data TEXT," + 733702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "image_id INTEGER," + 734702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "kind INTEGER," + 735702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "width INTEGER," + 736702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "height INTEGER" + 737702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 738702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 739702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE INDEX IF NOT EXISTS image_id_index on thumbnails(image_id);"); 740702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 741702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS thumbnails_cleanup DELETE ON thumbnails " + 742702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 743702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT _DELETE_FILE(old._data);" + 744702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 745702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 746702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains meta data about audio files 747702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS audio_meta (" + 748702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 749216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen "_data TEXT UNIQUE NOT NULL," + 750702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_display_name TEXT," + 751702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_size INTEGER," + 752702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "mime_type TEXT," + 753702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_added INTEGER," + 754702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_modified INTEGER," + 755702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "title TEXT NOT NULL," + 756702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "title_key TEXT NOT NULL," + 757702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "duration INTEGER," + 758702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "artist_id INTEGER," + 759702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "composer TEXT," + 760702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "album_id INTEGER," + 761702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "track INTEGER," + // track is an integer to allow proper sorting 762702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "year INTEGER CHECK(year!=0)," + 763702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "is_ringtone INTEGER," + 764702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "is_music INTEGER," + 765702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "is_alarm INTEGER," + 766702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "is_notification INTEGER" + 767702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 768702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 769702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains a sort/group "key" and the preferred display name for artists 770702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS artists (" + 771702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "artist_id INTEGER PRIMARY KEY," + 772702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "artist_key TEXT NOT NULL UNIQUE," + 773702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "artist TEXT NOT NULL" + 774702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 775702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 776702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains a sort/group "key" and the preferred display name for albums 777702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS albums (" + 778702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "album_id INTEGER PRIMARY KEY," + 779702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "album_key TEXT NOT NULL UNIQUE," + 780702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "album TEXT NOT NULL" + 781702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 782702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 783702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS album_art (" + 784702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "album_id INTEGER PRIMARY KEY," + 785702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_data TEXT" + 786702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 787702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 788702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project recreateAudioView(db); 78995ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen 790702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 791702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Provides some extra info about artists, like the number of tracks 792702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // and albums for this artist 793702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE VIEW IF NOT EXISTS artist_info AS " + 794702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT artist_id AS _id, artist, artist_key, " + 795acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen "COUNT(DISTINCT album) AS number_of_albums, " + 796702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "COUNT(*) AS number_of_tracks FROM audio WHERE is_music=1 "+ 797702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "GROUP BY artist_key;"); 798702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 799702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Provides extra info albums, such as the number of tracks 800702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE VIEW IF NOT EXISTS album_info AS " + 801702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT audio.album_id AS _id, album, album_key, " + 802702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "MIN(year) AS minyear, " + 803702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "MAX(year) AS maxyear, artist, artist_id, artist_key, " + 804702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "count(*) AS " + MediaStore.Audio.Albums.NUMBER_OF_SONGS + 805702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ",album_art._data AS album_art" + 806702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " FROM audio LEFT OUTER JOIN album_art ON audio.album_id=album_art.album_id" + 807702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " WHERE is_music=1 GROUP BY audio.album_id;"); 808702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 809acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // For a given artist_id, provides the album_id for albums on 810acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // which the artist appears. 811acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("CREATE VIEW IF NOT EXISTS artists_albums_map AS " + 812acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen "SELECT DISTINCT artist_id, album_id FROM audio_meta;"); 813acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen 814702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /* 815702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Only external media volumes can handle genres, playlists, etc. 816702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 817702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!internal) { 818702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Cleans up when an audio file is deleted 819702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS audio_meta_cleanup DELETE ON audio_meta " + 820702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 821702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE FROM audio_genres_map WHERE audio_id = old._id;" + 822702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE FROM audio_playlists_map WHERE audio_id = old._id;" + 823702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 824702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 825702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains audio genre definitions 826702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS audio_genres (" + 827702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 828702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "name TEXT NOT NULL" + 829702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 830702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 83178b2885edc406273d688536b0eadfea006b20662Marco Nelissen // Contains mappings between audio genres and audio files 832702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS audio_genres_map (" + 833702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 834702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_id INTEGER NOT NULL," + 835702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "genre_id INTEGER NOT NULL" + 836702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 837702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 838702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Cleans up when an audio genre is delete 839702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS audio_genres_cleanup DELETE ON audio_genres " + 840702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 841702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE FROM audio_genres_map WHERE genre_id = old._id;" + 842702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 843702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 844702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains audio playlist definitions 845702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS audio_playlists (" + 846702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 847702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_data TEXT," + // _data is path for file based playlists, or null 848702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "name TEXT NOT NULL," + 849702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_added INTEGER," + 850702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_modified INTEGER" + 851702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 852702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 853702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains mappings between audio playlists and audio files 854702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS audio_playlists_map (" + 855702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 856702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_id INTEGER NOT NULL," + 857702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "playlist_id INTEGER NOT NULL," + 858702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "play_order INTEGER NOT NULL" + 859702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 860702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 861702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Cleans up when an audio playlist is deleted 862702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS audio_playlists_cleanup DELETE ON audio_playlists " + 863702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 864702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE FROM audio_playlists_map WHERE playlist_id = old._id;" + 865702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT _DELETE_FILE(old._data);" + 866702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 867702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 868702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Cleans up album_art table entry when an album is deleted 869702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS albumart_cleanup1 DELETE ON albums " + 870702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 871702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE FROM album_art WHERE album_id = old.album_id;" + 872702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 873702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 874702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Cleans up album_art when an album is deleted 875702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS albumart_cleanup2 DELETE ON album_art " + 876702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 877702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT _DELETE_FILE(old._data);" + 878702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 879702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 880702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 881702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains meta data about video files 882702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS video (" + 883702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 884702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_data TEXT NOT NULL," + 885702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_display_name TEXT," + 886702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_size INTEGER," + 887702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "mime_type TEXT," + 888702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_added INTEGER," + 889702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_modified INTEGER," + 890702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "title TEXT," + 891702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "duration INTEGER," + 892702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "artist TEXT," + 893702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "album TEXT," + 894702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "resolution TEXT," + 895702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "description TEXT," + 896702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "isprivate INTEGER," + // for YouTube videos 897702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "tags TEXT," + // for YouTube videos 898702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "category TEXT," + // for YouTube videos 899702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "language TEXT," + // for YouTube videos 900702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "mini_thumb_data TEXT," + 901702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "latitude DOUBLE," + 902702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "longitude DOUBLE," + 903702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "datetaken INTEGER," + 904702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "mini_thumb_magic INTEGER" + 905702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 906702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 907702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS video_cleanup DELETE ON video " + 908702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 909702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT _DELETE_FILE(old._data);" + 910702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 911702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 912702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 913702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // At this point the database is at least at schema version 63 (it was 914702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // either created at version 63 by the code above, or was already at 915702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // version 63 or later) 916702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 917702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 64) { 918702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // create the index that updates the database to schema version 64 919702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE INDEX IF NOT EXISTS sort_index on images(datetaken ASC, _id ASC);"); 920702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 921702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 922acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen /* 923acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen * Android 1.0 shipped with database version 64 924acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen */ 925acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen 926702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 65) { 927702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // create the index that updates the database to schema version 65 928702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE INDEX IF NOT EXISTS titlekey_index on audio_meta(title_key);"); 929702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 930702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 931403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen // In version 66, originally we updateBucketNames(db, "images"), 932403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen // but we need to do it in version 89 and therefore save the update here. 933702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 934702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 67) { 935702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // create the indices that update the database to schema version 67 936702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE INDEX IF NOT EXISTS albumkey_index on albums(album_key);"); 937702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE INDEX IF NOT EXISTS artistkey_index on artists(artist_key);"); 938702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 939702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 940702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 68) { 941702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Create bucket_id and bucket_display_name columns for the video table. 942702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("ALTER TABLE video ADD COLUMN bucket_id TEXT;"); 943702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("ALTER TABLE video ADD COLUMN bucket_display_name TEXT"); 944403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen 945403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen // In version 68, originally we updateBucketNames(db, "video"), 946403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen // but we need to do it in version 89 and therefore save the update here. 947702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 948702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 949702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 69) { 950702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project updateDisplayName(db, "images"); 951702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 952702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 953702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 70) { 954702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Create bookmark column for the video table. 955702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("ALTER TABLE video ADD COLUMN bookmark INTEGER;"); 956702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 95795ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen 958702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 71) { 959702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // There is no change to the database schema, however a code change 960702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // fixed parsing of metadata for certain files bought from the 961702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // iTunes music store, so we want to rescan files that might need it. 962702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // We do this by clearing the modification date in the database for 963702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // those files, so that the media scanner will see them as updated 964702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // and rescan them. 965702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("UPDATE audio_meta SET date_modified=0 WHERE _id IN (" + 966702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT _id FROM audio where mime_type='audio/mp4' AND " + 967e31cfb1a2c21e7ac7a646d40afbb48f49fab6907Marco Nelissen "artist='" + MediaStore.UNKNOWN_STRING + "' AND " + 968e31cfb1a2c21e7ac7a646d40afbb48f49fab6907Marco Nelissen "album='" + MediaStore.UNKNOWN_STRING + "'" + 969702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 970702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 97195ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen 972702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 72) { 973702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Create is_podcast and bookmark columns for the audio table. 974702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("ALTER TABLE audio_meta ADD COLUMN is_podcast INTEGER;"); 975702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("UPDATE audio_meta SET is_podcast=1 WHERE _data LIKE '%/podcasts/%';"); 976702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("UPDATE audio_meta SET is_music=0 WHERE is_podcast=1" + 977702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " AND _data NOT LIKE '%/music/%';"); 978702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("ALTER TABLE audio_meta ADD COLUMN bookmark INTEGER;"); 979702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 980702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // New columns added to tables aren't visible in views on those tables 981702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // without opening and closing the database (or using the 'vacuum' command, 982702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // which we can't do here because all this code runs inside a transaction). 983702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // To work around this, we drop and recreate the affected view and trigger. 984702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project recreateAudioView(db); 985702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 98695ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen 987acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen /* 988acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen * Android 1.5 shipped with database version 72 989acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen */ 990acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen 9918d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen if (fromVersion < 73) { 9928d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen // There is no change to the database schema, but we now do case insensitive 9938d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen // matching of folder names when determining whether something is music, a 9948d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen // ringtone, podcast, etc, so we might need to reclassify some files. 9958d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen db.execSQL("UPDATE audio_meta SET is_music=1 WHERE is_music=0 AND " + 9968d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen "_data LIKE '%/music/%';"); 9978d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen db.execSQL("UPDATE audio_meta SET is_ringtone=1 WHERE is_ringtone=0 AND " + 9988d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen "_data LIKE '%/ringtones/%';"); 9998d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen db.execSQL("UPDATE audio_meta SET is_notification=1 WHERE is_notification=0 AND " + 10008d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen "_data LIKE '%/notifications/%';"); 10018d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen db.execSQL("UPDATE audio_meta SET is_alarm=1 WHERE is_alarm=0 AND " + 10028d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen "_data LIKE '%/alarms/%';"); 10038d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen db.execSQL("UPDATE audio_meta SET is_podcast=1 WHERE is_podcast=0 AND " + 10048d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen "_data LIKE '%/podcasts/%';"); 10058d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen } 1006a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen 1007a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen if (fromVersion < 74) { 1008a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // This view is used instead of the audio view by the union below, to force 1009a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // sqlite to use the title_key index. This greatly reduces memory usage 1010a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // (no separate copy pass needed for sorting, which could cause errors on 1011a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // large datasets) and improves speed (by about 35% on a large dataset) 1012a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen db.execSQL("CREATE VIEW IF NOT EXISTS searchhelpertitle AS SELECT * FROM audio " + 1013a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "ORDER BY title_key;"); 1014a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen 1015a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen db.execSQL("CREATE VIEW IF NOT EXISTS search AS " + 1016a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "SELECT _id," + 1017a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "'artist' AS mime_type," + 1018a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist," + 1019a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS album," + 1020a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS title," + 1021a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist AS text1," + 1022a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS text2," + 1023a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "number_of_albums AS data1," + 1024a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "number_of_tracks AS data2," + 1025a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist_key AS match," + 1026a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "'content://media/external/audio/artists/'||_id AS suggest_intent_data," + 1027a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "1 AS grouporder " + 1028e31cfb1a2c21e7ac7a646d40afbb48f49fab6907Marco Nelissen "FROM artist_info WHERE (artist!='" + MediaStore.UNKNOWN_STRING + "') " + 1029a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "UNION ALL " + 1030a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "SELECT _id," + 1031a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "'album' AS mime_type," + 1032a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist," + 1033a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "album," + 1034a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS title," + 1035a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "album AS text1," + 1036a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist AS text2," + 1037a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS data1," + 1038a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS data2," + 1039a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist_key||' '||album_key AS match," + 1040a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "'content://media/external/audio/albums/'||_id AS suggest_intent_data," + 1041a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "2 AS grouporder " + 1042e31cfb1a2c21e7ac7a646d40afbb48f49fab6907Marco Nelissen "FROM album_info WHERE (album!='" + MediaStore.UNKNOWN_STRING + "') " + 1043a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "UNION ALL " + 1044a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "SELECT searchhelpertitle._id AS _id," + 1045a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "mime_type," + 1046a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist," + 1047a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "album," + 1048a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "title," + 1049a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "title AS text1," + 1050a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist AS text2," + 1051a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS data1," + 1052a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS data2," + 1053a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist_key||' '||album_key||' '||title_key AS match," + 1054a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "'content://media/external/audio/media/'||searchhelpertitle._id AS " + 1055a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "suggest_intent_data," + 1056a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "3 AS grouporder " + 1057a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "FROM searchhelpertitle WHERE (title != '') " 1058a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen ); 1059a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen } 106059948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen 106159948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen if (fromVersion < 75) { 106295ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen // Force a rescan of the audio entries so we can apply the new logic to 106359948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // distinguish same-named albums. 106459948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen db.execSQL("UPDATE audio_meta SET date_modified=0;"); 106559948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen db.execSQL("DELETE FROM albums"); 106659948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen } 106715d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen 106815d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen if (fromVersion < 76) { 106915d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen // We now ignore double quotes when building the key, so we have to remove all of them 107015d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen // from existing keys. 107115d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen db.execSQL("UPDATE audio_meta SET title_key=" + 107215d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen "REPLACE(title_key,x'081D08C29F081D',x'081D') " + 107315d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen "WHERE title_key LIKE '%'||x'081D08C29F081D'||'%';"); 107415d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen db.execSQL("UPDATE albums SET album_key=" + 107515d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen "REPLACE(album_key,x'081D08C29F081D',x'081D') " + 107615d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen "WHERE album_key LIKE '%'||x'081D08C29F081D'||'%';"); 107715d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen db.execSQL("UPDATE artists SET artist_key=" + 107815d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen "REPLACE(artist_key,x'081D08C29F081D',x'081D') " + 107915d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen "WHERE artist_key LIKE '%'||x'081D08C29F081D'||'%';"); 108015d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen } 1081b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1082acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen /* 1083acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen * Android 1.6 shipped with database version 76 1084acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen */ 1085acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen 1086b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (fromVersion < 77) { 1087b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // create video thumbnail table 1088b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen db.execSQL("CREATE TABLE IF NOT EXISTS videothumbnails (" + 1089b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "_id INTEGER PRIMARY KEY," + 1090b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "_data TEXT," + 1091b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "video_id INTEGER," + 1092b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "kind INTEGER," + 1093b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "width INTEGER," + 1094b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "height INTEGER" + 1095b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen ");"); 1096b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1097b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen db.execSQL("CREATE INDEX IF NOT EXISTS video_id_index on videothumbnails(video_id);"); 1098b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1099b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen db.execSQL("CREATE TRIGGER IF NOT EXISTS videothumbnails_cleanup DELETE ON videothumbnails " + 1100b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "BEGIN " + 1101b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "SELECT _DELETE_FILE(old._data);" + 1102b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "END"); 1103b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 11041769168ade7b67f8695a4e4f3c69625aca0811d5Ray Chen 1105acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen /* 1106acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen * Android 2.0 and 2.0.1 shipped with database version 77 1107acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen */ 1108acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen 11091769168ade7b67f8695a4e4f3c69625aca0811d5Ray Chen if (fromVersion < 78) { 1110044b029d9023f55e8e8861ed2f6e192f1b34f9bbRay Chen // Force a rescan of the video entries so we can update 11111769168ade7b67f8695a4e4f3c69625aca0811d5Ray Chen // latest changed DATE_TAKEN units (in milliseconds). 11121769168ade7b67f8695a4e4f3c69625aca0811d5Ray Chen db.execSQL("UPDATE video SET date_modified=0;"); 11131769168ade7b67f8695a4e4f3c69625aca0811d5Ray Chen } 1114268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen 1115acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen /* 1116acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen * Android 2.1 shipped with database version 78 1117acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen */ 1118acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen 1119268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen if (fromVersion < 79) { 1120268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen // move /sdcard/albumthumbs to 1121268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen // /sdcard/Android/data/com.android.providers.media/albumthumbs, 1122268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen // and update the database accordingly 1123268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen 11249be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood String oldthumbspath = mExternalStoragePaths[0] + "/albumthumbs"; 11259be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood String newthumbspath = mExternalStoragePaths[0] + "/" + ALBUM_THUMB_FOLDER; 1126268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen File thumbsfolder = new File(oldthumbspath); 1127268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen if (thumbsfolder.exists()) { 1128268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen // move folder to its new location 1129268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen File newthumbsfolder = new File(newthumbspath); 1130268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen newthumbsfolder.getParentFile().mkdirs(); 1131268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen if(thumbsfolder.renameTo(newthumbsfolder)) { 1132268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen // update the database 1133268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen db.execSQL("UPDATE album_art SET _data=REPLACE(_data, '" + 1134268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen oldthumbspath + "','" + newthumbspath + "');"); 1135268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen } 1136268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen } 1137268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen } 1138044b029d9023f55e8e8861ed2f6e192f1b34f9bbRay Chen 1139044b029d9023f55e8e8861ed2f6e192f1b34f9bbRay Chen if (fromVersion < 80) { 1140044b029d9023f55e8e8861ed2f6e192f1b34f9bbRay Chen // Force rescan of image entries to update DATE_TAKEN as UTC timestamp. 1141044b029d9023f55e8e8861ed2f6e192f1b34f9bbRay Chen db.execSQL("UPDATE images SET date_modified=0;"); 1142044b029d9023f55e8e8861ed2f6e192f1b34f9bbRay Chen } 11430ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen 1144166a4e3cc66a645cc5e11d2f06d059512def0aceMarco Nelissen if (fromVersion < 81 && !internal) { 11450ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // Delete entries starting with /mnt/sdcard. This is for the benefit 11460ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // of users running builds between 2.0.1 and 2.1 final only, since 11470ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // users updating from 2.0 or earlier will not have such entries. 11480ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen 11490ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // First we need to update the _data fields in the affected tables, since 11500ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // otherwise deleting the entries will also delete the underlying files 11510ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // (via a trigger), and we want to keep them. 11520ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE audio_playlists SET _data='////' WHERE _data LIKE '/mnt/sdcard/%';"); 11530ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE images SET _data='////' WHERE _data LIKE '/mnt/sdcard/%';"); 11540ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE video SET _data='////' WHERE _data LIKE '/mnt/sdcard/%';"); 11550ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE videothumbnails SET _data='////' WHERE _data LIKE '/mnt/sdcard/%';"); 11560ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE thumbnails SET _data='////' WHERE _data LIKE '/mnt/sdcard/%';"); 11570ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE album_art SET _data='////' WHERE _data LIKE '/mnt/sdcard/%';"); 1158216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen db.execSQL("UPDATE audio_meta SET _data='////' WHERE _data LIKE '/mnt/sdcard/%';"); 11590ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // Once the paths have been renamed, we can safely delete the entries 11600ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE FROM audio_playlists WHERE _data IS '////';"); 11610ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE FROM images WHERE _data IS '////';"); 11620ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE FROM video WHERE _data IS '////';"); 11630ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE FROM videothumbnails WHERE _data IS '////';"); 11640ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE FROM thumbnails WHERE _data IS '////';"); 11650ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE FROM audio_meta WHERE _data IS '////';"); 11660ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE FROM album_art WHERE _data IS '////';"); 11670ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen 11680ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // rename existing entries starting with /sdcard to /mnt/sdcard 11690ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE audio_meta" + 11700ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen " SET _data='/mnt/sdcard'||SUBSTR(_data,8) WHERE _data LIKE '/sdcard/%';"); 11710ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE audio_playlists" + 11720ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen " SET _data='/mnt/sdcard'||SUBSTR(_data,8) WHERE _data LIKE '/sdcard/%';"); 11730ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE images" + 11740ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen " SET _data='/mnt/sdcard'||SUBSTR(_data,8) WHERE _data LIKE '/sdcard/%';"); 11750ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE video" + 11760ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen " SET _data='/mnt/sdcard'||SUBSTR(_data,8) WHERE _data LIKE '/sdcard/%';"); 11770ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE videothumbnails" + 11780ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen " SET _data='/mnt/sdcard'||SUBSTR(_data,8) WHERE _data LIKE '/sdcard/%';"); 11790ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE thumbnails" + 11800ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen " SET _data='/mnt/sdcard'||SUBSTR(_data,8) WHERE _data LIKE '/sdcard/%';"); 11810ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE album_art" + 11820ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen " SET _data='/mnt/sdcard'||SUBSTR(_data,8) WHERE _data LIKE '/sdcard/%';"); 11830ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen 11840ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // Delete albums and artists, then clear the modification time on songs, which 11850ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // will cause the media scanner to rescan everything, rebuilding the artist and 11860ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // album tables along the way, while preserving playlists. 11870ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // We need this rescan because ICU also changed, and now generates different 11880ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // collation keys 11890ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE from albums"); 11900ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE from artists"); 11910ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE audio_meta SET date_modified=0;"); 11920ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen } 119384403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen 119484403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen if (fromVersion < 82) { 1195acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // recreate this view with the correct "group by" specifier 119684403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen db.execSQL("DROP VIEW IF EXISTS artist_info"); 119784403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen db.execSQL("CREATE VIEW IF NOT EXISTS artist_info AS " + 119884403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen "SELECT artist_id AS _id, artist, artist_key, " + 1199acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen "COUNT(DISTINCT album_key) AS number_of_albums, " + 120084403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen "COUNT(*) AS number_of_tracks FROM audio WHERE is_music=1 "+ 120184403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen "GROUP BY artist_key;"); 120284403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen } 1203216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen 1204acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen /* we skipped over version 83, and reverted versions 84, 85 and 86 */ 1205ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen 1206ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen if (fromVersion < 87) { 1207ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen // The fastscroll thumb needs an index on the strings being displayed, 1208ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen // otherwise the queries it does to determine the correct position 1209ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen // becomes really inefficient 1210022eb71bfe8ec65b8817eaa432a530194210ec23Marco Nelissen db.execSQL("CREATE INDEX IF NOT EXISTS title_idx on audio_meta(title);"); 1211022eb71bfe8ec65b8817eaa432a530194210ec23Marco Nelissen db.execSQL("CREATE INDEX IF NOT EXISTS artist_idx on artists(artist);"); 1212022eb71bfe8ec65b8817eaa432a530194210ec23Marco Nelissen db.execSQL("CREATE INDEX IF NOT EXISTS album_idx on albums(album);"); 1213ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen } 1214216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen 1215acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen if (fromVersion < 88) { 1216acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // Clean up a few more things from versions 84/85/86, and recreate 1217acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // the few things worth keeping from those changes. 1218acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS albums_update1;"); 1219acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS albums_update2;"); 1220acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS albums_update3;"); 1221acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS albums_update4;"); 1222acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS artist_update1;"); 1223acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS artist_update2;"); 1224acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS artist_update3;"); 1225acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS artist_update4;"); 122616dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood db.execSQL("DROP VIEW IF EXISTS album_artists;"); 1227acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("CREATE INDEX IF NOT EXISTS album_id_idx on audio_meta(album_id);"); 1228acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("CREATE INDEX IF NOT EXISTS artist_id_idx on audio_meta(artist_id);"); 1229acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // For a given artist_id, provides the album_id for albums on 1230acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // which the artist appears. 1231acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("CREATE VIEW IF NOT EXISTS artists_albums_map AS " + 1232acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen "SELECT DISTINCT artist_id, album_id FROM audio_meta;"); 1233acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen } 1234403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen 1235fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood // In version 89, originally we updateBucketNames(db, "images") and 1236fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood // updateBucketNames(db, "video"), but in version 101 we now updateBucketNames 1237fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood // for all files and therefore can save the update here. 1238b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 1239b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood if (fromVersion < 91) { 1240bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin // Never query by mini_thumb_magic_index 1241bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin db.execSQL("DROP INDEX IF EXISTS mini_thumb_magic_index"); 1242bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin 1243bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin // sort the items by taken date in each bucket 1244bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin db.execSQL("CREATE INDEX IF NOT EXISTS image_bucket_index ON images(bucket_id, datetaken)"); 1245bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin db.execSQL("CREATE INDEX IF NOT EXISTS video_bucket_index ON video(bucket_id, datetaken)"); 1246bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin } 1247bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin 1248a36cfaef630ef5df7bef80b25f6bd493d040c7e4Brian Muramatsu 1249d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen // Gingerbread ended up going to version 100, but didn't yet have the "files" 1250d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen // table, so we need to create that if we're at 100 or lower. This means 1251d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen // we won't be able to upgrade pre-release Honeycomb. 1252d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen if (fromVersion <= 100) { 1253afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // Remove various stages of work in progress for MTP support 1254afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TABLE IF EXISTS objects"); 1255afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TABLE IF EXISTS files"); 125616dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood db.execSQL("DROP TRIGGER IF EXISTS images_objects_cleanup;"); 125716dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood db.execSQL("DROP TRIGGER IF EXISTS audio_objects_cleanup;"); 125816dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood db.execSQL("DROP TRIGGER IF EXISTS video_objects_cleanup;"); 125916dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood db.execSQL("DROP TRIGGER IF EXISTS playlists_objects_cleanup;"); 1260afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TRIGGER IF EXISTS files_cleanup_images;"); 1261afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TRIGGER IF EXISTS files_cleanup_audio;"); 1262afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TRIGGER IF EXISTS files_cleanup_video;"); 1263afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TRIGGER IF EXISTS files_cleanup_playlists;"); 1264afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TRIGGER IF EXISTS media_cleanup;"); 1265afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1266afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // Create a new table to manage all files in our storage. 1267afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // This contains a union of all the columns from the old 1268afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // images, audio_meta, videos and audio_playlist tables. 1269afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE TABLE files (" + 127000a22306f6c99d1f1b4424f8f6a1cad8fb332d85Ray Chen "_id INTEGER PRIMARY KEY AUTOINCREMENT," + 1271afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "_data TEXT," + // this can be null for playlists 1272afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "_size INTEGER," + 1273afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "format INTEGER," + 1274afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "parent INTEGER," + 1275afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "date_added INTEGER," + 1276afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "date_modified INTEGER," + 1277afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "mime_type TEXT," + 1278afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "title TEXT," + 1279afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "description TEXT," + 1280afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "_display_name TEXT," + 1281afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1282afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // for images 1283afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "picasa_id TEXT," + 1284afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "orientation INTEGER," + 1285afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1286afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // for images and video 1287afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "latitude DOUBLE," + 1288afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "longitude DOUBLE," + 1289afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "datetaken INTEGER," + 1290afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "mini_thumb_magic INTEGER," + 1291afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "bucket_id TEXT," + 1292afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "bucket_display_name TEXT," + 1293afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "isprivate INTEGER," + 1294afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1295afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // for audio 1296afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "title_key TEXT," + 1297afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "artist_id INTEGER," + 1298afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "album_id INTEGER," + 1299afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "composer TEXT," + 1300afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "track INTEGER," + 1301afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "year INTEGER CHECK(year!=0)," + 1302afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "is_ringtone INTEGER," + 1303afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "is_music INTEGER," + 1304afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "is_alarm INTEGER," + 1305afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "is_notification INTEGER," + 1306afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "is_podcast INTEGER," + 1307d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen "album_artist TEXT," + 1308afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1309afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // for audio and video 1310afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "duration INTEGER," + 1311afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "bookmark INTEGER," + 1312afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1313afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // for video 1314afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "artist TEXT," + 1315afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "album TEXT," + 1316afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "resolution TEXT," + 1317afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "tags TEXT," + 1318afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "category TEXT," + 1319afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "language TEXT," + 1320afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "mini_thumb_data TEXT," + 1321afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1322afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // for playlists 1323afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "name TEXT," + 1324afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1325afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // media_type is used by the views to emulate the old 1326afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // images, audio_meta, videos and audio_playlist tables. 1327afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "media_type INTEGER," + 1328afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1329afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // Value of _id from the old media table. 1330afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // Used only for updating other tables during database upgrade. 1331afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "old_id INTEGER" + 1332afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood ");"); 1333d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen 1334afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE INDEX path_index ON files(_data);"); 1335afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE INDEX media_type_index ON files(media_type);"); 1336afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1337afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // Copy all data from our obsolete tables to the new files table 133892be385568284e6351ab49f5799eca0e35b9d98dMike Lockwood 133992be385568284e6351ab49f5799eca0e35b9d98dMike Lockwood // Copy audio records first, preserving the _id column. 134092be385568284e6351ab49f5799eca0e35b9d98dMike Lockwood // We do this to maintain compatibility for content Uris for ringtones. 134192be385568284e6351ab49f5799eca0e35b9d98dMike Lockwood // Unfortunately we cannot do this for images and videos as well. 134292be385568284e6351ab49f5799eca0e35b9d98dMike Lockwood // We choose to do this for the audio table because the fragility of Uris 134392be385568284e6351ab49f5799eca0e35b9d98dMike Lockwood // for ringtones are the most common problem we need to avoid. 134492be385568284e6351ab49f5799eca0e35b9d98dMike Lockwood db.execSQL("INSERT INTO files (_id," + AUDIO_COLUMNSv99 + ",old_id,media_type)" + 134592be385568284e6351ab49f5799eca0e35b9d98dMike Lockwood " SELECT _id," + AUDIO_COLUMNSv99 + ",_id," + FileColumns.MEDIA_TYPE_AUDIO + 134692be385568284e6351ab49f5799eca0e35b9d98dMike Lockwood " FROM audio_meta;"); 134792be385568284e6351ab49f5799eca0e35b9d98dMike Lockwood 1348bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang db.execSQL("INSERT INTO files (" + IMAGE_COLUMNSv407 + ",old_id,media_type) SELECT " 1349bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang + IMAGE_COLUMNSv407 + ",_id," + FileColumns.MEDIA_TYPE_IMAGE + " FROM images;"); 1350bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang db.execSQL("INSERT INTO files (" + VIDEO_COLUMNSv407 + ",old_id,media_type) SELECT " 1351bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang + VIDEO_COLUMNSv407 + ",_id," + FileColumns.MEDIA_TYPE_VIDEO + " FROM video;"); 135216dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood if (!internal) { 1353afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("INSERT INTO files (" + PLAYLIST_COLUMNS + ",old_id,media_type) SELECT " 1354afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + PLAYLIST_COLUMNS + ",_id," + FileColumns.MEDIA_TYPE_PLAYLIST 1355afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + " FROM audio_playlists;"); 1356afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 135716dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood 1358afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // Delete the old tables 1359afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TABLE IF EXISTS images"); 1360afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TABLE IF EXISTS audio_meta"); 1361afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TABLE IF EXISTS video"); 1362afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TABLE IF EXISTS audio_playlists"); 136316dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood 1364afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // Create views to replace our old tables 1365bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang db.execSQL("CREATE VIEW images AS SELECT _id," + IMAGE_COLUMNSv407 + 1366afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood " FROM files WHERE " + FileColumns.MEDIA_TYPE + "=" 1367afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + FileColumns.MEDIA_TYPE_IMAGE + ";"); 1368d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen db.execSQL("CREATE VIEW audio_meta AS SELECT _id," + AUDIO_COLUMNSv100 + 1369d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen " FROM files WHERE " + FileColumns.MEDIA_TYPE + "=" 1370d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen + FileColumns.MEDIA_TYPE_AUDIO + ";"); 1371bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang db.execSQL("CREATE VIEW video AS SELECT _id," + VIDEO_COLUMNSv407 + 1372afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood " FROM files WHERE " + FileColumns.MEDIA_TYPE + "=" 1373afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + FileColumns.MEDIA_TYPE_VIDEO + ";"); 1374afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (!internal) { 1375afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE VIEW audio_playlists AS SELECT _id," + PLAYLIST_COLUMNS + 1376afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood " FROM files WHERE " + FileColumns.MEDIA_TYPE + "=" 1377afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + FileColumns.MEDIA_TYPE_PLAYLIST + ";"); 137816dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood } 137936339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood 13809491c3bd011644f5fe69fd47f73d0e1245b33febMarco Nelissen // create temporary index to make the updates go faster 13819491c3bd011644f5fe69fd47f73d0e1245b33febMarco Nelissen db.execSQL("CREATE INDEX tmp ON files(old_id);"); 13829491c3bd011644f5fe69fd47f73d0e1245b33febMarco Nelissen 1383afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // update the image_id column in the thumbnails table. 1384afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("UPDATE thumbnails SET image_id = (SELECT _id FROM files " 1385afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + "WHERE files.old_id = thumbnails.image_id AND files.media_type = " 1386afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + FileColumns.MEDIA_TYPE_IMAGE + ");"); 138736339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood 1388afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (!internal) { 1389d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen // update audio_id in the audio_genres_map table, and 1390d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen // audio_playlists_map tables and playlist_id in the audio_playlists_map table 1391afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("UPDATE audio_genres_map SET audio_id = (SELECT _id FROM files " 1392afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + "WHERE files.old_id = audio_genres_map.audio_id AND files.media_type = " 1393afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + FileColumns.MEDIA_TYPE_AUDIO + ");"); 1394afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("UPDATE audio_playlists_map SET audio_id = (SELECT _id FROM files " 1395afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + "WHERE files.old_id = audio_playlists_map.audio_id " 1396afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + "AND files.media_type = " + FileColumns.MEDIA_TYPE_AUDIO + ");"); 1397d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen db.execSQL("UPDATE audio_playlists_map SET playlist_id = (SELECT _id FROM files " 1398d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen + "WHERE files.old_id = audio_playlists_map.playlist_id " 1399d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen + "AND files.media_type = " + FileColumns.MEDIA_TYPE_PLAYLIST + ");"); 1400afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 1401afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1402afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // update video_id in the videothumbnails table. 1403afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("UPDATE videothumbnails SET video_id = (SELECT _id FROM files " 1404afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + "WHERE files.old_id = videothumbnails.video_id AND files.media_type = " 1405afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + FileColumns.MEDIA_TYPE_VIDEO + ");"); 1406afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 14079491c3bd011644f5fe69fd47f73d0e1245b33febMarco Nelissen // we don't need this index anymore now 14089491c3bd011644f5fe69fd47f73d0e1245b33febMarco Nelissen db.execSQL("DROP INDEX tmp;"); 14099491c3bd011644f5fe69fd47f73d0e1245b33febMarco Nelissen 1410afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // update indices to work on the files table 1411afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP INDEX IF EXISTS title_idx"); 1412afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP INDEX IF EXISTS album_id_idx"); 1413afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP INDEX IF EXISTS image_bucket_index"); 1414afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP INDEX IF EXISTS video_bucket_index"); 1415afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP INDEX IF EXISTS sort_index"); 1416afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP INDEX IF EXISTS titlekey_index"); 1417afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP INDEX IF EXISTS artist_id_idx"); 1418afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE INDEX title_idx ON files(title);"); 1419afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE INDEX album_id_idx ON files(album_id);"); 1420afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE INDEX bucket_index ON files(bucket_id, datetaken);"); 1421afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE INDEX sort_index ON files(datetaken ASC, _id ASC);"); 1422afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE INDEX titlekey_index ON files(title_key);"); 1423afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE INDEX artist_id_idx ON files(artist_id);"); 1424afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1425afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // Recreate triggers for our obsolete tables on the new files table 1426afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TRIGGER IF EXISTS images_cleanup"); 1427afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TRIGGER IF EXISTS audio_meta_cleanup"); 1428afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TRIGGER IF EXISTS video_cleanup"); 1429afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TRIGGER IF EXISTS audio_playlists_cleanup"); 1430afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TRIGGER IF EXISTS audio_delete"); 143136339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood 1432afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE TRIGGER IF NOT EXISTS images_cleanup DELETE ON files " + 1433afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "WHEN old.media_type = " + FileColumns.MEDIA_TYPE_IMAGE + " " + 143436339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood "BEGIN " + 1435afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "DELETE FROM thumbnails WHERE image_id = old._id;" + 1436afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "SELECT _DELETE_FILE(old._data);" + 143736339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood "END"); 143836339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood 1439afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE TRIGGER IF NOT EXISTS video_cleanup DELETE ON files " + 144049dea76284f7693ba452c05cfd59c1d9c9584343Ray Chen "WHEN old.media_type = " + FileColumns.MEDIA_TYPE_VIDEO + " " + 144136339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood "BEGIN " + 1442afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "SELECT _DELETE_FILE(old._data);" + 144336339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood "END"); 144436339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood 1445afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (!internal) { 1446afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE TRIGGER IF NOT EXISTS audio_meta_cleanup DELETE ON files " + 1447afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "WHEN old.media_type = " + FileColumns.MEDIA_TYPE_AUDIO + " " + 1448afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "BEGIN " + 1449afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "DELETE FROM audio_genres_map WHERE audio_id = old._id;" + 1450afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "DELETE FROM audio_playlists_map WHERE audio_id = old._id;" + 1451afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "END"); 1452afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1453afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE TRIGGER IF NOT EXISTS audio_playlists_cleanup DELETE ON files " + 1454afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "WHEN old.media_type = " + FileColumns.MEDIA_TYPE_PLAYLIST + " " + 1455afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "BEGIN " + 1456afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "DELETE FROM audio_playlists_map WHERE playlist_id = old._id;" + 1457afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "SELECT _DELETE_FILE(old._data);" + 1458afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "END"); 1459afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1460afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE TRIGGER IF NOT EXISTS audio_delete INSTEAD OF DELETE ON audio " + 146136339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood "BEGIN " + 1462afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "DELETE from files where _id=old._id;" + 1463afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "DELETE from audio_playlists_map where audio_id=old._id;" + 1464afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "DELETE from audio_genres_map where audio_id=old._id;" + 146536339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood "END"); 146636339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood } 146736339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood } 146836339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood 1469fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood if (fromVersion < 300) { 1470fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood // we now compute bucket and display names for all files to avoid problems with files 1471fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood // that the media scanner might not recognize as images or videos 1472fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood updateBucketNames(db, "files"); 1473fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood } 1474fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood 1475db8357b2b2888ce3778278e9cd9e698347ca6105Owen Lin if (fromVersion < 301) { 1476db8357b2b2888ce3778278e9cd9e698347ca6105Owen Lin db.execSQL("DROP INDEX IF EXISTS bucket_index"); 1477db8357b2b2888ce3778278e9cd9e698347ca6105Owen Lin db.execSQL("CREATE INDEX bucket_index on files(bucket_id, media_type, datetaken, _id)"); 1478db8357b2b2888ce3778278e9cd9e698347ca6105Owen Lin db.execSQL("CREATE INDEX bucket_name on files(bucket_id, media_type, bucket_display_name)"); 1479db8357b2b2888ce3778278e9cd9e698347ca6105Owen Lin } 1480db8357b2b2888ce3778278e9cd9e698347ca6105Owen Lin 148120405fab4cf752dbdec6f1020bfc70a2bf87590eMike Lockwood if (fromVersion < 302) { 148220405fab4cf752dbdec6f1020bfc70a2bf87590eMike Lockwood db.execSQL("CREATE INDEX parent_index ON files(parent);"); 148320405fab4cf752dbdec6f1020bfc70a2bf87590eMike Lockwood db.execSQL("CREATE INDEX format_index ON files(format);"); 148420405fab4cf752dbdec6f1020bfc70a2bf87590eMike Lockwood } 148520405fab4cf752dbdec6f1020bfc70a2bf87590eMike Lockwood 14862658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen if (fromVersion < 303) { 14872658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen // the album disambiguator hash changed, so rescan songs and force 14882658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen // albums to be updated. Artists are unaffected. 14892658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen db.execSQL("DELETE from albums"); 14902658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen db.execSQL("UPDATE files SET date_modified=0 WHERE " + FileColumns.MEDIA_TYPE + "=" 14912658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen + FileColumns.MEDIA_TYPE_AUDIO + ";"); 14922658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen } 14932658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen 14944b5963f15c1563c613ec505ca7962f93aec44321Mike Lockwood if (fromVersion < 304 && !internal) { 149551d6c5d233f78de2db9b3f63514b20b1ce768dd5Mike Lockwood // notifies host when files are deleted 149651d6c5d233f78de2db9b3f63514b20b1ce768dd5Mike Lockwood db.execSQL("CREATE TRIGGER IF NOT EXISTS files_cleanup DELETE ON files " + 149751d6c5d233f78de2db9b3f63514b20b1ce768dd5Mike Lockwood "BEGIN " + 149851d6c5d233f78de2db9b3f63514b20b1ce768dd5Mike Lockwood "SELECT _OBJECT_REMOVED(old._id);" + 149951d6c5d233f78de2db9b3f63514b20b1ce768dd5Mike Lockwood "END"); 150051d6c5d233f78de2db9b3f63514b20b1ce768dd5Mike Lockwood 150151d6c5d233f78de2db9b3f63514b20b1ce768dd5Mike Lockwood } 150251d6c5d233f78de2db9b3f63514b20b1ce768dd5Mike Lockwood 15034b5963f15c1563c613ec505ca7962f93aec44321Mike Lockwood if (fromVersion < 305 && internal) { 15044b5963f15c1563c613ec505ca7962f93aec44321Mike Lockwood // version 304 erroneously added this trigger to the internal database 15054b5963f15c1563c613ec505ca7962f93aec44321Mike Lockwood db.execSQL("DROP TRIGGER IF EXISTS files_cleanup"); 15064b5963f15c1563c613ec505ca7962f93aec44321Mike Lockwood } 15074b5963f15c1563c613ec505ca7962f93aec44321Mike Lockwood 1508fda522dc66b94057f9c6676cb8ba10bc3b13daeaMarco Nelissen if (fromVersion < 306 && !internal) { 1509efe0bcdf5ed215a5cb76c8a48aad1333056636f4Marco Nelissen // The genre list was expanded and genre string parsing was tweaked, so 1510efe0bcdf5ed215a5cb76c8a48aad1333056636f4Marco Nelissen // rebuild the genre list 1511efe0bcdf5ed215a5cb76c8a48aad1333056636f4Marco Nelissen db.execSQL("UPDATE files SET date_modified=0 WHERE " + FileColumns.MEDIA_TYPE + "=" 1512efe0bcdf5ed215a5cb76c8a48aad1333056636f4Marco Nelissen + FileColumns.MEDIA_TYPE_AUDIO + ";"); 1513efe0bcdf5ed215a5cb76c8a48aad1333056636f4Marco Nelissen db.execSQL("DELETE FROM audio_genres_map"); 1514efe0bcdf5ed215a5cb76c8a48aad1333056636f4Marco Nelissen db.execSQL("DELETE FROM audio_genres"); 1515efe0bcdf5ed215a5cb76c8a48aad1333056636f4Marco Nelissen } 1516efe0bcdf5ed215a5cb76c8a48aad1333056636f4Marco Nelissen 151765587f9c204abb2d179527dfdca009f4780e9743Ray Chen if (fromVersion < 307 && !internal) { 151865587f9c204abb2d179527dfdca009f4780e9743Ray Chen // Force rescan of image entries to update DATE_TAKEN by either GPSTimeStamp or 151965587f9c204abb2d179527dfdca009f4780e9743Ray Chen // EXIF local time. 152065587f9c204abb2d179527dfdca009f4780e9743Ray Chen db.execSQL("UPDATE files SET date_modified=0 WHERE " + FileColumns.MEDIA_TYPE + "=" 152165587f9c204abb2d179527dfdca009f4780e9743Ray Chen + FileColumns.MEDIA_TYPE_IMAGE + ";"); 152265587f9c204abb2d179527dfdca009f4780e9743Ray Chen } 152365587f9c204abb2d179527dfdca009f4780e9743Ray Chen 15244f63f7c1e6f602a77abd43b189f296b9eb36635bMike Lockwood // Database version 401 did not add storage_id to the internal database. 15254f63f7c1e6f602a77abd43b189f296b9eb36635bMike Lockwood // We need it there too, so add it in version 402 15264f63f7c1e6f602a77abd43b189f296b9eb36635bMike Lockwood if (fromVersion < 401 || (fromVersion == 401 && internal)) { 15279be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood // Add column for MTP storage ID 15289be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood db.execSQL("ALTER TABLE files ADD COLUMN storage_id INTEGER;"); 15299be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood // Anything in the database before this upgrade step will be in the primary storage 15309be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood db.execSQL("UPDATE files SET storage_id=" + MtpStorage.getStorageId(0) + ";"); 15319be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood } 15329be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood 153378b2885edc406273d688536b0eadfea006b20662Marco Nelissen if (fromVersion < 403 && !internal) { 153478b2885edc406273d688536b0eadfea006b20662Marco Nelissen db.execSQL("CREATE VIEW audio_genres_map_noid AS " + 153578b2885edc406273d688536b0eadfea006b20662Marco Nelissen "SELECT audio_id,genre_id from audio_genres_map;"); 153678b2885edc406273d688536b0eadfea006b20662Marco Nelissen } 153778b2885edc406273d688536b0eadfea006b20662Marco Nelissen 15389289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen if (fromVersion < 404) { 15399289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen // There was a bug that could cause distinct same-named albums to be 15409289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen // combined again. Delete albums and force a rescan. 15419289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen db.execSQL("DELETE from albums"); 15429289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen db.execSQL("UPDATE files SET date_modified=0 WHERE " + FileColumns.MEDIA_TYPE + "=" 15439289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen + FileColumns.MEDIA_TYPE_AUDIO + ";"); 15449289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen } 15459289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen 1546957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang if (fromVersion < 405) { 1547957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang // Add is_drm column. 1548957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang db.execSQL("ALTER TABLE files ADD COLUMN is_drm INTEGER;"); 1549957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang 1550957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang db.execSQL("DROP VIEW IF EXISTS audio_meta"); 1551957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang db.execSQL("CREATE VIEW audio_meta AS SELECT _id," + AUDIO_COLUMNSv405 + 1552957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang " FROM files WHERE " + FileColumns.MEDIA_TYPE + "=" 1553957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang + FileColumns.MEDIA_TYPE_AUDIO + ";"); 1554957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang 1555957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang recreateAudioView(db); 1556957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang } 1557957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang 1558b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood if (fromVersion < 407) { 15597ee82723c70fc02b168cfa9b6ff7d5fdd0c16d53Gloria Wang // Rescan files in the media database because a new column has been added 1560b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood // in table files in version 405 and to recover from problems populating 1561b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood // the genre tables 15627ee82723c70fc02b168cfa9b6ff7d5fdd0c16d53Gloria Wang db.execSQL("UPDATE files SET date_modified=0;"); 15637ee82723c70fc02b168cfa9b6ff7d5fdd0c16d53Gloria Wang } 15647ee82723c70fc02b168cfa9b6ff7d5fdd0c16d53Gloria Wang 1565bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang if (fromVersion < 408) { 1566bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang // Add the width/height columns for images and video 1567bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang db.execSQL("ALTER TABLE files ADD COLUMN width INTEGER;"); 1568bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang db.execSQL("ALTER TABLE files ADD COLUMN height INTEGER;"); 1569bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang 1570bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang // Rescan files to fill the columns 1571bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang db.execSQL("UPDATE files SET date_modified=0;"); 1572bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang 1573bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang // Update images and video views to contain the width/height columns 1574bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang db.execSQL("DROP VIEW IF EXISTS images"); 1575bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang db.execSQL("DROP VIEW IF EXISTS video"); 1576bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang db.execSQL("CREATE VIEW images AS SELECT _id," + IMAGE_COLUMNS + 1577bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang " FROM files WHERE " + FileColumns.MEDIA_TYPE + "=" 1578bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang + FileColumns.MEDIA_TYPE_IMAGE + ";"); 1579bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang db.execSQL("CREATE VIEW video AS SELECT _id," + VIDEO_COLUMNS + 1580bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang " FROM files WHERE " + FileColumns.MEDIA_TYPE + "=" 1581bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang + FileColumns.MEDIA_TYPE_VIDEO + ";"); 1582bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang } 1583bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang 1584acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen sanityCheck(db, fromVersion); 15851d4a8ec9e1e62427088dc40f08872a10c863535eMarco Nelissen } 15861d4a8ec9e1e62427088dc40f08872a10c863535eMarco Nelissen 15871d4a8ec9e1e62427088dc40f08872a10c863535eMarco Nelissen /** 1588216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen * Perform a simple sanity check on the database. Currently this tests 1589216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen * whether all the _data entries in audio_meta are unique 1590216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen */ 1591216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen private static void sanityCheck(SQLiteDatabase db, int fromVersion) { 1592216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen Cursor c1 = db.query("audio_meta", new String[] {"count(*)"}, 1593216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen null, null, null, null, null); 1594216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen Cursor c2 = db.query("audio_meta", new String[] {"count(distinct _data)"}, 1595216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen null, null, null, null, null); 1596216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen c1.moveToFirst(); 1597216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen c2.moveToFirst(); 1598216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen int num1 = c1.getInt(0); 1599216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen int num2 = c2.getInt(0); 1600216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen c1.close(); 1601216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen c2.close(); 1602216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen if (num1 != num2) { 1603216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen Log.e(TAG, "audio_meta._data column is not unique while upgrading" + 1604216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen " from schema " +fromVersion + " : " + num1 +"/" + num2); 1605216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen // Delete all audio_meta rows so they will be rebuilt by the media scanner 1606216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen db.execSQL("DELETE FROM audio_meta;"); 1607216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen } 1608702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1609702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1610702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static void recreateAudioView(SQLiteDatabase db) { 1611702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Provides a unified audio/artist/album info view. 1612702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Note that views are read-only, so we define a trigger to allow deletes. 1613702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP VIEW IF EXISTS audio"); 1614702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS audio_delete"); 1615702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE VIEW IF NOT EXISTS audio as SELECT * FROM audio_meta " + 1616702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "LEFT OUTER JOIN artists ON audio_meta.artist_id=artists.artist_id " + 1617702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "LEFT OUTER JOIN albums ON audio_meta.album_id=albums.album_id;"); 1618702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1619702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS audio_delete INSTEAD OF DELETE ON audio " + 1620702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 1621702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE from audio_meta where _id=old._id;" + 1622702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE from audio_playlists_map where audio_id=old._id;" + 1623702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE from audio_genres_map where audio_id=old._id;" + 1624702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 1625702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 162695ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen 1627702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 1628702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Iterate through the rows of a table in a database, ensuring that the bucket_id and 1629702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * bucket_display_name columns are correct. 1630702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param db 1631702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param tableName 1632702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 1633702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static void updateBucketNames(SQLiteDatabase db, String tableName) { 1634702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Rebuild the bucket_display_name column using the natural case rather than lower case. 1635702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.beginTransaction(); 1636702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 1637702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String[] columns = {BaseColumns._ID, MediaColumns.DATA}; 1638702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Cursor cursor = db.query(tableName, columns, null, null, null, null, null); 1639702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 1640702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final int idColumnIndex = cursor.getColumnIndex(BaseColumns._ID); 1641702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final int dataColumnIndex = cursor.getColumnIndex(MediaColumns.DATA); 16429491c3bd011644f5fe69fd47f73d0e1245b33febMarco Nelissen String [] rowId = new String[1]; 1643702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project while (cursor.moveToNext()) { 1644702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String data = cursor.getString(dataColumnIndex); 16459491c3bd011644f5fe69fd47f73d0e1245b33febMarco Nelissen rowId[0] = String.valueOf(cursor.getInt(idColumnIndex)); 1646d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen if (data != null) { 1647d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen ContentValues values = new ContentValues(); 1648d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen computeBucketValues(data, values); 16499491c3bd011644f5fe69fd47f73d0e1245b33febMarco Nelissen db.update(tableName, values, "_id=?", rowId); 1650d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen } else { 1651d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen Log.w(TAG, "null data at id " + rowId); 1652d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen } 1653702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1654702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 1655702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project cursor.close(); 1656702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1657702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.setTransactionSuccessful(); 1658702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 1659702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.endTransaction(); 1660702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1661702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1662702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1663702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 1664702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Iterate through the rows of a table in a database, ensuring that the 1665702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * display name column has a value. 1666702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param db 1667702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param tableName 1668702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 1669702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static void updateDisplayName(SQLiteDatabase db, String tableName) { 1670702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Fill in default values for null displayName values 1671702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.beginTransaction(); 1672702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 1673702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String[] columns = {BaseColumns._ID, MediaColumns.DATA, MediaColumns.DISPLAY_NAME}; 1674702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Cursor cursor = db.query(tableName, columns, null, null, null, null, null); 1675702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 1676702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final int idColumnIndex = cursor.getColumnIndex(BaseColumns._ID); 1677702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final int dataColumnIndex = cursor.getColumnIndex(MediaColumns.DATA); 1678702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final int displayNameIndex = cursor.getColumnIndex(MediaColumns.DISPLAY_NAME); 1679702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(); 1680702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project while (cursor.moveToNext()) { 1681702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String displayName = cursor.getString(displayNameIndex); 1682702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (displayName == null) { 1683702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String data = cursor.getString(dataColumnIndex); 1684702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.clear(); 1685702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project computeDisplayName(data, values); 1686702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int rowId = cursor.getInt(idColumnIndex); 1687702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.update(tableName, values, "_id=" + rowId, null); 1688702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1689702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1690702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 1691702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project cursor.close(); 1692702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1693702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.setTransactionSuccessful(); 1694702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 1695702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.endTransaction(); 1696702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1697702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1698702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 1699702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param data The input path 1700702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param values the content values, where the bucked id name and bucket display name are updated. 1701702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 1702702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 1703702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1704702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static void computeBucketValues(String data, ContentValues values) { 1705702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File parentFile = new File(data).getParentFile(); 1706702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (parentFile == null) { 1707702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project parentFile = new File("/"); 1708702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1709702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1710702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Lowercase the path for hashing. This avoids duplicate buckets if the 1711702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // filepath case is changed externally. 1712702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Keep the original case for display. 1713702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String path = parentFile.toString().toLowerCase(); 1714702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String name = parentFile.getName(); 1715702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1716702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Note: the BUCKET_ID and BUCKET_DISPLAY_NAME attributes are spelled the 1717702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // same for both images and video. However, for backwards-compatibility reasons 1718702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // there is no common base class. We use the ImageColumns version here 1719d0d809c65db7d4936266c8f6a18511046c84fd15Mike Lockwood values.put(ImageColumns.BUCKET_ID, path.hashCode()); 1720702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(ImageColumns.BUCKET_DISPLAY_NAME, name); 1721702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1722702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1723702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 1724702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param data The input path 1725702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param values the content values, where the display name is updated. 1726702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 1727702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 1728702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static void computeDisplayName(String data, ContentValues values) { 1729702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String s = (data == null ? "" : data.toString()); 1730702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int idx = s.lastIndexOf('/'); 1731702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (idx >= 0) { 1732702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project s = s.substring(idx + 1); 1733702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1734702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put("_display_name", s); 1735702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1736702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1737b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen /** 1738498b62c2912302a23532c73a028a7684c5df33caRay Chen * Copy taken time from date_modified if we lost the original value (e.g. after factory reset) 1739498b62c2912302a23532c73a028a7684c5df33caRay Chen * This works for both video and image tables. 1740b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen * 1741b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen * @param values the content values, where taken time is updated. 1742b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen */ 1743b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen private static void computeTakenTime(ContentValues values) { 1744b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen if (! values.containsKey(Images.Media.DATE_TAKEN)) { 1745b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen // This only happens when MediaScanner finds an image file that doesn't have any useful 1746b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen // reference to get this value. (e.g. GPSTimeStamp) 1747498b62c2912302a23532c73a028a7684c5df33caRay Chen Long lastModified = values.getAsLong(MediaColumns.DATE_MODIFIED); 1748b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen if (lastModified != null) { 1749b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen values.put(Images.Media.DATE_TAKEN, lastModified * 1000); 1750b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen } 1751b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen } 1752b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen } 1753b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen 1754b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen /** 1755b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen * This method blocks until thumbnail is ready. 1756b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen * 1757b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen * @param thumbUri 1758b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen * @return 1759b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen */ 1760b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private boolean waitForThumbnailReady(Uri origUri) { 1761b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen Cursor c = this.query(origUri, new String[] { ImageColumns._ID, ImageColumns.DATA, 1762b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen ImageColumns.MINI_THUMB_MAGIC}, null, null, null); 1763b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (c == null) return false; 1764b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1765b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen boolean result = false; 1766b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1767b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (c.moveToFirst()) { 1768e263c2a4b880ef8a5314bb4379c74bf5f9292bd0Ray Chen long id = c.getLong(0); 1769b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen String path = c.getString(1); 1770b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen long magic = c.getLong(2); 1771b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 17729299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen MediaThumbRequest req = requestMediaThumbnail(path, origUri, 17739299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen MediaThumbRequest.PRIORITY_HIGH, magic); 17749299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen if (req == null) { 17759299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen return false; 17769299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen } 17779299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen synchronized (req) { 17789299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen try { 17799299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen while (req.mState == MediaThumbRequest.State.WAIT) { 17809299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen req.wait(); 178120434e032e498b716f87cce2f23dd646819218bfRay Chen } 17829299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen } catch (InterruptedException e) { 17839299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen Log.w(TAG, e); 17849299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen } 17859299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen if (req.mState == MediaThumbRequest.State.DONE) { 17869299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen result = true; 1787b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1788b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1789b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1790b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen c.close(); 1791b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1792b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return result; 1793b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1794b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1795e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen private boolean matchThumbRequest(MediaThumbRequest req, int pid, long id, long gid, 1796e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen boolean isVideo) { 1797e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen boolean cancelAllOrigId = (id == -1); 1798e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen boolean cancelAllGroupId = (gid == -1); 1799e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen return (req.mCallingPid == pid) && 1800e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen (cancelAllGroupId || req.mGroupId == gid) && 1801e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen (cancelAllOrigId || req.mOrigId == id) && 1802e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen (req.mIsVideo == isVideo); 1803e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen } 1804e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen 1805b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private boolean queryThumbnail(SQLiteQueryBuilder qb, Uri uri, String table, 1806b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen String column, boolean hasThumbnailId) { 1807b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen qb.setTables(table); 1808b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (hasThumbnailId) { 1809b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // For uri dispatched to this method, the 4th path segment is always 1810b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // the thumbnail id. 1811b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen qb.appendWhere("_id = " + uri.getPathSegments().get(3)); 1812b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // client already knows which thumbnail it wants, bypass it. 1813b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return true; 1814b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1815b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen String origId = uri.getQueryParameter("orig_id"); 1816b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // We can't query ready_flag unless we know original id 1817b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (origId == null) { 1818b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // this could be thumbnail query for other purpose, bypass it. 1819b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return true; 1820b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1821b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1822b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen boolean needBlocking = "1".equals(uri.getQueryParameter("blocking")); 182320434e032e498b716f87cce2f23dd646819218bfRay Chen boolean cancelRequest = "1".equals(uri.getQueryParameter("cancel")); 1824e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen Uri origUri = uri.buildUpon().encodedPath( 1825e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen uri.getPath().replaceFirst("thumbnails", "media")) 1826e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen .appendPath(origId).build(); 1827b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1828b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (needBlocking && !waitForThumbnailReady(origUri)) { 182920434e032e498b716f87cce2f23dd646819218bfRay Chen Log.w(TAG, "original media doesn't exist or it's canceled."); 1830b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return false; 183120434e032e498b716f87cce2f23dd646819218bfRay Chen } else if (cancelRequest) { 1832e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen String groupId = uri.getQueryParameter("group_id"); 1833e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen boolean isVideo = "video".equals(uri.getPathSegments().get(1)); 183420434e032e498b716f87cce2f23dd646819218bfRay Chen int pid = Binder.getCallingPid(); 183520434e032e498b716f87cce2f23dd646819218bfRay Chen long id = -1; 1836e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen long gid = -1; 1837e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen 183820434e032e498b716f87cce2f23dd646819218bfRay Chen try { 183920434e032e498b716f87cce2f23dd646819218bfRay Chen id = Long.parseLong(origId); 1840e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen gid = Long.parseLong(groupId); 184120434e032e498b716f87cce2f23dd646819218bfRay Chen } catch (NumberFormatException ex) { 184220434e032e498b716f87cce2f23dd646819218bfRay Chen // invalid cancel request 184320434e032e498b716f87cce2f23dd646819218bfRay Chen return false; 184420434e032e498b716f87cce2f23dd646819218bfRay Chen } 1845e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen 184620434e032e498b716f87cce2f23dd646819218bfRay Chen synchronized (mMediaThumbQueue) { 1847e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen if (mCurrentThumbRequest != null && 1848e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen matchThumbRequest(mCurrentThumbRequest, pid, id, gid, isVideo)) { 184920434e032e498b716f87cce2f23dd646819218bfRay Chen synchronized (mCurrentThumbRequest) { 185020434e032e498b716f87cce2f23dd646819218bfRay Chen mCurrentThumbRequest.mState = MediaThumbRequest.State.CANCEL; 185120434e032e498b716f87cce2f23dd646819218bfRay Chen mCurrentThumbRequest.notifyAll(); 185220434e032e498b716f87cce2f23dd646819218bfRay Chen } 185320434e032e498b716f87cce2f23dd646819218bfRay Chen } 185420434e032e498b716f87cce2f23dd646819218bfRay Chen for (MediaThumbRequest mtq : mMediaThumbQueue) { 1855e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen if (matchThumbRequest(mtq, pid, id, gid, isVideo)) { 185620434e032e498b716f87cce2f23dd646819218bfRay Chen synchronized (mtq) { 185720434e032e498b716f87cce2f23dd646819218bfRay Chen mtq.mState = MediaThumbRequest.State.CANCEL; 185820434e032e498b716f87cce2f23dd646819218bfRay Chen mtq.notifyAll(); 185920434e032e498b716f87cce2f23dd646819218bfRay Chen } 186020434e032e498b716f87cce2f23dd646819218bfRay Chen 186120434e032e498b716f87cce2f23dd646819218bfRay Chen mMediaThumbQueue.remove(mtq); 186220434e032e498b716f87cce2f23dd646819218bfRay Chen } 186320434e032e498b716f87cce2f23dd646819218bfRay Chen } 186420434e032e498b716f87cce2f23dd646819218bfRay Chen } 1865b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1866b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1867b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (origId != null) { 1868b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen qb.appendWhere(column + " = " + origId); 1869b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1870b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return true; 1871b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1872b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen @SuppressWarnings("fallthrough") 1873702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 1874702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public Cursor query(Uri uri, String[] projectionIn, String selection, 1875702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String[] selectionArgs, String sort) { 1876702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int table = URI_MATCHER.match(uri); 1877baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen List<String> prependArgs = new ArrayList<String>(); 1878702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 187901a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen // Log.v(TAG, "query: uri="+uri+", selection="+selection); 1880702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // handle MEDIA_SCANNER before calling getDatabaseForUri() 1881702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (table == MEDIA_SCANNER) { 1882702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (mMediaScannerVolume == null) { 1883702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return null; 1884702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 1885702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // create a cursor to return volume currently being scanned by the media scanner 18860027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen MatrixCursor c = new MatrixCursor(new String[] {MediaStore.MEDIA_SCANNER_VOLUME}); 18870027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen c.addRow(new String[] {mMediaScannerVolume}); 18880027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen return c; 1889702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1890702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1891702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 18920027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen // Used temporarily (until we have unique media IDs) to get an identifier 18930027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen // for the current sd card, so that the music app doesn't have to use the 18940027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen // non-public getFatVolumeId method 18950027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen if (table == FS_ID) { 18960027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen MatrixCursor c = new MatrixCursor(new String[] {"fsid"}); 18970027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen c.addRow(new Integer[] {mVolumeId}); 18980027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen return c; 18990027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen } 19000027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen 1901704a8b507b7aa61a09457075ed6f80c95914d731Marco Nelissen if (table == VERSION) { 1902704a8b507b7aa61a09457075ed6f80c95914d731Marco Nelissen MatrixCursor c = new MatrixCursor(new String[] {"version"}); 1903704a8b507b7aa61a09457075ed6f80c95914d731Marco Nelissen c.addRow(new Integer[] {DATABASE_VERSION}); 1904704a8b507b7aa61a09457075ed6f80c95914d731Marco Nelissen return c; 1905704a8b507b7aa61a09457075ed6f80c95914d731Marco Nelissen } 1906704a8b507b7aa61a09457075ed6f80c95914d731Marco Nelissen 1907702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String groupBy = null; 190810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen DatabaseHelper helper = getDatabaseForUri(uri); 190910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen if (helper == null) { 1910702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return null; 1911702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 191210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumQueries++; 191310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen SQLiteDatabase db = helper.getReadableDatabase(); 19145fde670987a55d69442566dcbdb7830d5f1587c6Chih-Chung Chang if (db == null) return null; 1915702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 19164574e03055af60fada50481f2b34e19a687d5866Marco Nelissen String limit = uri.getQueryParameter("limit"); 1917c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen String filter = uri.getQueryParameter("filter"); 1918c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen String [] keywords = null; 1919c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen if (filter != null) { 1920c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen filter = Uri.decode(filter).trim(); 1921c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen if (!TextUtils.isEmpty(filter)) { 1922c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen String [] searchWords = filter.split(" "); 1923c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen keywords = new String[searchWords.length]; 1924c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen Collator col = Collator.getInstance(); 1925c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen col.setStrength(Collator.PRIMARY); 1926c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen for (int i = 0; i < searchWords.length; i++) { 1927c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen String key = MediaStore.Audio.keyFor(searchWords[i]); 1928c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen key = key.replace("\\", "\\\\"); 1929c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen key = key.replace("%", "\\%"); 1930c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen key = key.replace("_", "\\_"); 1931c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen keywords[i] = key; 1932c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen } 1933c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen } 1934c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen } 1935db8357b2b2888ce3778278e9cd9e698347ca6105Owen Lin if (uri.getQueryParameter("distinct") != null) { 1936db8357b2b2888ce3778278e9cd9e698347ca6105Owen Lin qb.setDistinct(true); 1937db8357b2b2888ce3778278e9cd9e698347ca6105Owen Lin } 1938c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen 1939b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen boolean hasThumbnailId = false; 1940702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1941702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (table) { 1942702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA: 1943702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("images"); 1944702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (uri.getQueryParameter("distinct") != null) 1945702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setDistinct(true); 1946702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1947702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // set the project map so that data dir is prepended to _data. 1948702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project //qb.setProjectionMap(mImagesProjectionMap, true); 1949702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1950702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1951702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA_ID: 1952702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("images"); 1953702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (uri.getQueryParameter("distinct") != null) 1954702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setDistinct(true); 1955702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1956702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // set the project map so that data dir is prepended to _data. 1957702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project //qb.setProjectionMap(mImagesProjectionMap, true); 1958baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen qb.appendWhere("_id=?"); 1959baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(3)); 1960702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1961702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1962702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_THUMBNAILS_ID: 1963b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen hasThumbnailId = true; 1964b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case IMAGES_THUMBNAILS: 1965b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (!queryThumbnail(qb, uri, "thumbnails", "image_id", hasThumbnailId)) { 1966b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return null; 1967b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1968702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1969702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1970702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA: 1971d9672f4d28ab9038333a0037fe30e386ac0ce610Marco Nelissen if (projectionIn != null && projectionIn.length == 1 && selectionArgs == null 1972ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen && (selection == null || selection.equalsIgnoreCase("is_music=1") 1973ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen || selection.equalsIgnoreCase("is_podcast=1") ) 1974c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen && projectionIn[0].equalsIgnoreCase("count(*)") 1975c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen && keywords != null) { 1976ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen //Log.i("@@@@", "taking fast path for counting songs"); 1977ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.setTables("audio_meta"); 1978ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen } else { 1979ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.setTables("audio"); 1980c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen for (int i = 0; keywords != null && i < keywords.length; i++) { 1981c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen if (i > 0) { 1982c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen qb.appendWhere(" AND "); 1983c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen } 1984c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen qb.appendWhere(MediaStore.Audio.Media.ARTIST_KEY + 1985c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen "||" + MediaStore.Audio.Media.ALBUM_KEY + 1986baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen "||" + MediaStore.Audio.Media.TITLE_KEY + " LIKE ? ESCAPE '\\'"); 1987baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add("%" + keywords[i] + "%"); 1988c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen } 1989ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen } 1990702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1991702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1992702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID: 1993702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio"); 1994baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen qb.appendWhere("_id=?"); 1995baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(3)); 1996702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1997702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1998702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES: 1999702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_genres"); 2000702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id IN (SELECT genre_id FROM " + 2001baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen "audio_genres_map WHERE audio_id=?)"); 2002baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(3)); 2003702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2004702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2005702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES_ID: 2006702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_genres"); 2007baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen qb.appendWhere("_id=?"); 2008baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(5)); 2009702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2010702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2011702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS: 2012702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_playlists"); 2013702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id IN (SELECT playlist_id FROM " + 2014baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen "audio_playlists_map WHERE audio_id=?)"); 2015baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(3)); 2016702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2017702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2018702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS_ID: 2019702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_playlists"); 2020baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen qb.appendWhere("_id=?"); 2021baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(5)); 2022702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2023702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2024702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES: 2025702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_genres"); 2026702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2027702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2028702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID: 2029702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_genres"); 2030baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen qb.appendWhere("_id=?"); 2031baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(3)); 2032702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2033702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2034bfbc30ff3b9e3a96b08c525d0971d8d8543ab000Marco Nelissen case AUDIO_GENRES_ALL_MEMBERS: 2035702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID_MEMBERS: 203678b2885edc406273d688536b0eadfea006b20662Marco Nelissen { 203778b2885edc406273d688536b0eadfea006b20662Marco Nelissen // if simpleQuery is true, we can do a simpler query on just audio_genres_map 203878b2885edc406273d688536b0eadfea006b20662Marco Nelissen // we can do this if we have no keywords and our projection includes just columns 203978b2885edc406273d688536b0eadfea006b20662Marco Nelissen // from audio_genres_map 204078b2885edc406273d688536b0eadfea006b20662Marco Nelissen boolean simpleQuery = (keywords == null && projectionIn != null 204178b2885edc406273d688536b0eadfea006b20662Marco Nelissen && (selection == null || selection.equalsIgnoreCase("genre_id=?"))); 204278b2885edc406273d688536b0eadfea006b20662Marco Nelissen if (projectionIn != null) { 204378b2885edc406273d688536b0eadfea006b20662Marco Nelissen for (int i = 0; i < projectionIn.length; i++) { 204478b2885edc406273d688536b0eadfea006b20662Marco Nelissen String p = projectionIn[i]; 204578b2885edc406273d688536b0eadfea006b20662Marco Nelissen if (p.equals("_id")) { 204678b2885edc406273d688536b0eadfea006b20662Marco Nelissen // note, this is different from playlist below, because 204778b2885edc406273d688536b0eadfea006b20662Marco Nelissen // "_id" used to (wrongly) be the audio id in this query, not 204878b2885edc406273d688536b0eadfea006b20662Marco Nelissen // the row id of the entry in the map, and we preserve this 204978b2885edc406273d688536b0eadfea006b20662Marco Nelissen // behavior for backwards compatibility 205078b2885edc406273d688536b0eadfea006b20662Marco Nelissen simpleQuery = false; 205178b2885edc406273d688536b0eadfea006b20662Marco Nelissen } 205278b2885edc406273d688536b0eadfea006b20662Marco Nelissen if (simpleQuery && !(p.equals("audio_id") || 205378b2885edc406273d688536b0eadfea006b20662Marco Nelissen p.equals("genre_id"))) { 205478b2885edc406273d688536b0eadfea006b20662Marco Nelissen simpleQuery = false; 205578b2885edc406273d688536b0eadfea006b20662Marco Nelissen } 205678b2885edc406273d688536b0eadfea006b20662Marco Nelissen } 205778b2885edc406273d688536b0eadfea006b20662Marco Nelissen } 205878b2885edc406273d688536b0eadfea006b20662Marco Nelissen if (simpleQuery) { 205978b2885edc406273d688536b0eadfea006b20662Marco Nelissen qb.setTables("audio_genres_map_noid"); 2060bfbc30ff3b9e3a96b08c525d0971d8d8543ab000Marco Nelissen if (table == AUDIO_GENRES_ID_MEMBERS) { 2061baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen qb.appendWhere("genre_id=?"); 2062baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(3)); 2063bfbc30ff3b9e3a96b08c525d0971d8d8543ab000Marco Nelissen } 206478b2885edc406273d688536b0eadfea006b20662Marco Nelissen } else { 206578b2885edc406273d688536b0eadfea006b20662Marco Nelissen qb.setTables("audio_genres_map_noid, audio"); 2066bfbc30ff3b9e3a96b08c525d0971d8d8543ab000Marco Nelissen qb.appendWhere("audio._id = audio_id"); 2067bfbc30ff3b9e3a96b08c525d0971d8d8543ab000Marco Nelissen if (table == AUDIO_GENRES_ID_MEMBERS) { 2068baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen qb.appendWhere(" AND genre_id=?"); 2069baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(3)); 2070bfbc30ff3b9e3a96b08c525d0971d8d8543ab000Marco Nelissen } 207178b2885edc406273d688536b0eadfea006b20662Marco Nelissen for (int i = 0; keywords != null && i < keywords.length; i++) { 207278b2885edc406273d688536b0eadfea006b20662Marco Nelissen qb.appendWhere(" AND "); 207378b2885edc406273d688536b0eadfea006b20662Marco Nelissen qb.appendWhere(MediaStore.Audio.Media.ARTIST_KEY + 207478b2885edc406273d688536b0eadfea006b20662Marco Nelissen "||" + MediaStore.Audio.Media.ALBUM_KEY + 207578b2885edc406273d688536b0eadfea006b20662Marco Nelissen "||" + MediaStore.Audio.Media.TITLE_KEY + 2076baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen " LIKE ? ESCAPE '\\'"); 2077baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add("%" + keywords[i] + "%"); 207878b2885edc406273d688536b0eadfea006b20662Marco Nelissen } 207978b2885edc406273d688536b0eadfea006b20662Marco Nelissen } 208078b2885edc406273d688536b0eadfea006b20662Marco Nelissen } 2081702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2082702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2083702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS: 2084702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_playlists"); 2085702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2086702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2087702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID: 2088702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_playlists"); 2089baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen qb.appendWhere("_id=?"); 2090baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(3)); 2091702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2092702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2093b5f293f3888b304e0b78c0039d7326c20e778b9fMarco Nelissen case AUDIO_PLAYLISTS_ID_MEMBERS_ID: 2094702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS: 2095e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood // if simpleQuery is true, we can do a simpler query on just audio_playlists_map 2096e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood // we can do this if we have no keywords and our projection includes just columns 2097e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood // from audio_playlists_map 20984382d5ecf11d3c70eed9ba7b09970ef254774b6dMike Lockwood boolean simpleQuery = (keywords == null && projectionIn != null 20994382d5ecf11d3c70eed9ba7b09970ef254774b6dMike Lockwood && (selection == null || selection.equalsIgnoreCase("playlist_id=?"))); 210097e61d89d90a1bd6989a254660aa80553662e002Marco Nelissen if (projectionIn != null) { 210197e61d89d90a1bd6989a254660aa80553662e002Marco Nelissen for (int i = 0; i < projectionIn.length; i++) { 2102e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood String p = projectionIn[i]; 2103e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood if (simpleQuery && !(p.equals("audio_id") || 2104e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood p.equals("playlist_id") || p.equals("play_order"))) { 2105e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood simpleQuery = false; 2106e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood } 2107e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood if (p.equals("_id")) { 210897e61d89d90a1bd6989a254660aa80553662e002Marco Nelissen projectionIn[i] = "audio_playlists_map._id AS _id"; 210997e61d89d90a1bd6989a254660aa80553662e002Marco Nelissen } 2110702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2111702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2112e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood if (simpleQuery) { 2113e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood qb.setTables("audio_playlists_map"); 2114baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen qb.appendWhere("playlist_id=?"); 2115baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(3)); 2116e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood } else { 2117e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood qb.setTables("audio_playlists_map, audio"); 2118baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen qb.appendWhere("audio._id = audio_id AND playlist_id=?"); 2119baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(3)); 2120e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood for (int i = 0; keywords != null && i < keywords.length; i++) { 2121e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood qb.appendWhere(" AND "); 2122e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood qb.appendWhere(MediaStore.Audio.Media.ARTIST_KEY + 2123e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood "||" + MediaStore.Audio.Media.ALBUM_KEY + 2124e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood "||" + MediaStore.Audio.Media.TITLE_KEY + 2125baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen " LIKE ? ESCAPE '\\'"); 2126baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add("%" + keywords[i] + "%"); 2127e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood } 2128c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen } 2129b5f293f3888b304e0b78c0039d7326c20e778b9fMarco Nelissen if (table == AUDIO_PLAYLISTS_ID_MEMBERS_ID) { 2130baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen qb.appendWhere(" AND audio_playlists_map._id=?"); 2131baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(5)); 2132b5f293f3888b304e0b78c0039d7326c20e778b9fMarco Nelissen } 2133702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2134702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2135702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA: 2136702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("video"); 2137702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2138702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA_ID: 2139702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("video"); 2140baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen qb.appendWhere("_id=?"); 2141baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(3)); 2142702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2143702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2144b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case VIDEO_THUMBNAILS_ID: 2145b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen hasThumbnailId = true; 2146b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case VIDEO_THUMBNAILS: 2147b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (!queryThumbnail(qb, uri, "videothumbnails", "video_id", hasThumbnailId)) { 2148b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return null; 2149b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 2150b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen break; 2151b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 2152702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ARTISTS: 2153d9672f4d28ab9038333a0037fe30e386ac0ce610Marco Nelissen if (projectionIn != null && projectionIn.length == 1 && selectionArgs == null 2154ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen && (selection == null || selection.length() == 0) 2155c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen && projectionIn[0].equalsIgnoreCase("count(*)") 2156c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen && keywords != null) { 2157ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen //Log.i("@@@@", "taking fast path for counting artists"); 2158ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.setTables("audio_meta"); 2159ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen projectionIn[0] = "count(distinct artist_id)"; 2160ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.appendWhere("is_music=1"); 2161ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen } else { 2162ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.setTables("artist_info"); 2163c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen for (int i = 0; keywords != null && i < keywords.length; i++) { 2164c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen if (i > 0) { 2165c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen qb.appendWhere(" AND "); 2166c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen } 2167c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen qb.appendWhere(MediaStore.Audio.Media.ARTIST_KEY + 2168baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen " LIKE ? ESCAPE '\\'"); 2169baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add("%" + keywords[i] + "%"); 2170c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen } 2171ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen } 2172702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2173702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2174702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ARTISTS_ID: 2175702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("artist_info"); 2176baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen qb.appendWhere("_id=?"); 2177baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(3)); 2178702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2179702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2180702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ARTISTS_ID_ALBUMS: 2181702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String aid = uri.getPathSegments().get(3); 2182acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen qb.setTables("audio LEFT OUTER JOIN album_art ON" + 2183acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen " audio.album_id=album_art.album_id"); 2184acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen qb.appendWhere("is_music=1 AND audio.album_id IN (SELECT album_id FROM " + 2185baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen "artists_albums_map WHERE artist_id=?)"); 2186baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(aid); 2187c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen for (int i = 0; keywords != null && i < keywords.length; i++) { 2188c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen qb.appendWhere(" AND "); 2189c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen qb.appendWhere(MediaStore.Audio.Media.ARTIST_KEY + 2190c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen "||" + MediaStore.Audio.Media.ALBUM_KEY + 2191baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen " LIKE ? ESCAPE '\\'"); 2192baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add("%" + keywords[i] + "%"); 2193c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen } 2194acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen groupBy = "audio.album_id"; 2195702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Albums.NUMBER_OF_SONGS_FOR_ARTIST, 2196acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen "count(CASE WHEN artist_id==" + aid + " THEN 'foo' ELSE NULL END) AS " + 2197702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.Audio.Albums.NUMBER_OF_SONGS_FOR_ARTIST); 2198702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setProjectionMap(sArtistAlbumsMap); 2199702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2200702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2201702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ALBUMS: 2202d9672f4d28ab9038333a0037fe30e386ac0ce610Marco Nelissen if (projectionIn != null && projectionIn.length == 1 && selectionArgs == null 2203ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen && (selection == null || selection.length() == 0) 2204c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen && projectionIn[0].equalsIgnoreCase("count(*)") 2205c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen && keywords != null) { 2206ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen //Log.i("@@@@", "taking fast path for counting albums"); 2207ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.setTables("audio_meta"); 2208ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen projectionIn[0] = "count(distinct album_id)"; 2209ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.appendWhere("is_music=1"); 2210ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen } else { 2211ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.setTables("album_info"); 2212c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen for (int i = 0; keywords != null && i < keywords.length; i++) { 2213c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen if (i > 0) { 2214c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen qb.appendWhere(" AND "); 2215c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen } 2216c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen qb.appendWhere(MediaStore.Audio.Media.ARTIST_KEY + 2217c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen "||" + MediaStore.Audio.Media.ALBUM_KEY + 2218baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen " LIKE ? ESCAPE '\\'"); 2219baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add("%" + keywords[i] + "%"); 2220c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen } 2221ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen } 2222702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2223702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2224702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ALBUMS_ID: 2225702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("album_info"); 2226baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen qb.appendWhere("_id=?"); 2227baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(3)); 2228702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2229702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2230702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ALBUMART_ID: 2231702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("album_art"); 2232baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen qb.appendWhere("album_id=?"); 2233baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(3)); 2234702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2235702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2236a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen case AUDIO_SEARCH_LEGACY: 2237a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen Log.w(TAG, "Legacy media search Uri used. Please update your code."); 2238a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // fall through 2239a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen case AUDIO_SEARCH_FANCY: 2240a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen case AUDIO_SEARCH_BASIC: 2241baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen return doAudioSearch(db, qb, uri, projectionIn, selection, 2242baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen combine(prependArgs, selectionArgs), sort, table, limit); 2243702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 224416dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood case FILES_ID: 2245e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood case MTP_OBJECTS_ID: 2246baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen qb.appendWhere("_id=?"); 2247baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(2)); 2248b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood // fall through 224916dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood case FILES: 2250e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood case MTP_OBJECTS: 225116dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood qb.setTables("files"); 2252b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood break; 2253b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 2254e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood case MTP_OBJECT_REFERENCES: 2255e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood int handle = Integer.parseInt(uri.getPathSegments().get(2)); 225610af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen return getObjectReferences(helper, db, handle); 2257e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood 2258702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project default: 2259702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalStateException("Unknown URL: " + uri.toString()); 2260702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2261702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2262baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen // Log.v(TAG, "query = "+ qb.buildQuery(projectionIn, selection, 2263baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen // combine(prependArgs, selectionArgs), groupBy, null, sort, limit)); 2264702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Cursor c = qb.query(db, projectionIn, selection, 2265baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen combine(prependArgs, selectionArgs), groupBy, null, sort, limit); 2266b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 2267702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (c != null) { 2268702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project c.setNotificationUri(getContext().getContentResolver(), uri); 2269702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2270b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 2271702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return c; 2272702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2273702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2274baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen private String[] combine(List<String> prepend, String[] userArgs) { 2275baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen int presize = prepend.size(); 2276baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen if (presize == 0) { 2277baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen return userArgs; 2278baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen } 2279baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen 2280baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen int usersize = (userArgs != null) ? userArgs.length : 0; 2281baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen String [] combined = new String[presize + usersize]; 2282baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen for (int i = 0; i < presize; i++) { 2283baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen combined[i] = prepend.get(i); 2284baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen } 2285baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen for (int i = 0; i < usersize; i++) { 2286baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen combined[presize + i] = userArgs[i]; 2287baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen } 2288baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen return combined; 2289baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen } 2290baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen 2291702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private Cursor doAudioSearch(SQLiteDatabase db, SQLiteQueryBuilder qb, 2292702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Uri uri, String[] projectionIn, String selection, 22934574e03055af60fada50481f2b34e19a687d5866Marco Nelissen String[] selectionArgs, String sort, int mode, 22944574e03055af60fada50481f2b34e19a687d5866Marco Nelissen String limit) { 2295702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 229618c787fb045725bf10bf630ac0917a48def9ace5Marco Nelissen String mSearchString = uri.getPath().endsWith("/") ? "" : uri.getLastPathSegment(); 2297702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mSearchString = mSearchString.replaceAll(" ", " ").trim().toLowerCase(); 2298702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2299702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String [] searchWords = mSearchString.length() > 0 ? 2300702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mSearchString.split(" ") : new String[0]; 2301a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen String [] wildcardWords = new String[searchWords.length]; 2302702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Collator col = Collator.getInstance(); 2303702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project col.setStrength(Collator.PRIMARY); 2304702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int len = searchWords.length; 2305702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project for (int i = 0; i < len; i++) { 2306702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Because we match on individual words here, we need to remove words 2307702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // like 'a' and 'the' that aren't part of the keys. 23083001ef332046c69cbb70289be29442fcc0ad5f6fMarco Nelissen String key = MediaStore.Audio.keyFor(searchWords[i]); 23093001ef332046c69cbb70289be29442fcc0ad5f6fMarco Nelissen key = key.replace("\\", "\\\\"); 23103001ef332046c69cbb70289be29442fcc0ad5f6fMarco Nelissen key = key.replace("%", "\\%"); 23113001ef332046c69cbb70289be29442fcc0ad5f6fMarco Nelissen key = key.replace("_", "\\_"); 2312a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen wildcardWords[i] = 2313702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project (searchWords[i].equals("a") || searchWords[i].equals("an") || 23143001ef332046c69cbb70289be29442fcc0ad5f6fMarco Nelissen searchWords[i].equals("the")) ? "%" : "%" + key + "%"; 2315702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2316702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2317a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen String where = ""; 2318a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen for (int i = 0; i < searchWords.length; i++) { 2319a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen if (i == 0) { 23203001ef332046c69cbb70289be29442fcc0ad5f6fMarco Nelissen where = "match LIKE ? ESCAPE '\\'"; 2321a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen } else { 23223001ef332046c69cbb70289be29442fcc0ad5f6fMarco Nelissen where += " AND match LIKE ? ESCAPE '\\'"; 2323702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2324702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2325702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2326a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen qb.setTables("search"); 2327a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen String [] cols; 2328a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen if (mode == AUDIO_SEARCH_FANCY) { 2329a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen cols = mSearchColsFancy; 2330a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen } else if (mode == AUDIO_SEARCH_BASIC) { 2331a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen cols = mSearchColsBasic; 2332a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen } else { 2333a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen cols = mSearchColsLegacy; 2334702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 23354574e03055af60fada50481f2b34e19a687d5866Marco Nelissen return qb.query(db, cols, where, wildcardWords, null, null, null, limit); 2336702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2337702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2338702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 2339702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public String getType(Uri url) 2340702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project { 2341702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (URI_MATCHER.match(url)) { 2342702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA_ID: 2343702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID: 2344702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS_ID: 2345702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA_ID: 2346c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood case FILES_ID: 234726f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen Cursor c = null; 234826f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen try { 234926f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen c = query(url, MIME_TYPE_PROJECTION, null, null, null); 235026f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen if (c != null && c.getCount() == 1) { 235126f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen c.moveToFirst(); 235226f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen String mimeType = c.getString(1); 235326f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen c.deactivate(); 235426f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen return mimeType; 235526f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen } 235626f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen } finally { 235726f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen if (c != null) { 235826f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen c.close(); 235926f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen } 2360702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2361702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2362702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2363702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA: 2364702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_THUMBNAILS: 2365702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Images.Media.CONTENT_TYPE; 2366804f5fe841d4a96f9335ea60d60853352f726227Marco Nelissen case AUDIO_ALBUMART_ID: 2367702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_THUMBNAILS_ID: 2368702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return "image/jpeg"; 2369702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2370702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA: 2371702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID_MEMBERS: 2372702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS: 2373702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Audio.Media.CONTENT_TYPE; 2374702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2375702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES: 2376702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES: 2377702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Audio.Genres.CONTENT_TYPE; 2378702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID: 2379702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES_ID: 2380702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Audio.Genres.ENTRY_CONTENT_TYPE; 2381702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS: 2382702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS: 2383702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Audio.Playlists.CONTENT_TYPE; 2384702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID: 2385702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS_ID: 2386702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Audio.Playlists.ENTRY_CONTENT_TYPE; 2387702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2388702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA: 2389702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Video.Media.CONTENT_TYPE; 2390702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2391804f5fe841d4a96f9335ea60d60853352f726227Marco Nelissen throw new IllegalStateException("Unknown URL : " + url); 2392702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2393702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2394702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 2395702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Ensures there is a file in the _data column of values, if one isn't 2396702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * present a new file is created. 2397702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 2398702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param initialValues the values passed to insert by the caller 2399702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @return the new values 2400702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 2401702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private ContentValues ensureFile(boolean internal, ContentValues initialValues, 2402702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String preferredExtension, String directoryName) { 2403702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values; 2404801ba04ac37ee06dccb8bf4081b29a162795e3a6Mike Lockwood String file = initialValues.getAsString(MediaStore.MediaColumns.DATA); 2405702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (TextUtils.isEmpty(file)) { 2406702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project file = generateFileName(internal, preferredExtension, directoryName); 2407702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values = new ContentValues(initialValues); 2408801ba04ac37ee06dccb8bf4081b29a162795e3a6Mike Lockwood values.put(MediaStore.MediaColumns.DATA, file); 2409702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 2410702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values = initialValues; 2411702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2412702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2413702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!ensureFileExists(file)) { 2414702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalStateException("Unable to create new file: " + file); 2415702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2416702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return values; 2417702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2418702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2419d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood private void sendObjectAdded(long objectHandle) { 242034be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood synchronized (mMtpServiceConnection) { 242134be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood if (mMtpService != null) { 242234be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood try { 242334be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood mMtpService.sendObjectAdded((int)objectHandle); 242434be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood } catch (RemoteException e) { 242534be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood Log.e(TAG, "RemoteException in sendObjectAdded", e); 242634be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood mMtpService = null; 242734be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood } 2428d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 2429d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 2430d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 2431d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 2432d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood private void sendObjectRemoved(long objectHandle) { 243334be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood synchronized (mMtpServiceConnection) { 243434be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood if (mMtpService != null) { 243534be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood try { 243634be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood mMtpService.sendObjectRemoved((int)objectHandle); 243734be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood } catch (RemoteException e) { 243834be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood Log.e(TAG, "RemoteException in sendObjectRemoved", e); 243934be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood mMtpService = null; 244034be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood } 2441d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 2442d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 2443d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 2444d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 2445702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 2446702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public int bulkInsert(Uri uri, ContentValues values[]) { 2447702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int match = URI_MATCHER.match(uri); 2448702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (match == VOLUMES) { 2449702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return super.bulkInsert(uri, values); 2450702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 245110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen DatabaseHelper helper = getDatabaseForUri(uri); 245210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen if (helper == null) { 2453702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException( 2454702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Unknown URI: " + uri); 2455702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 245610af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen SQLiteDatabase db = helper.getWritableDatabase(); 24575fde670987a55d69442566dcbdb7830d5f1587c6Chih-Chung Chang if (db == null) { 24585fde670987a55d69442566dcbdb7830d5f1587c6Chih-Chung Chang throw new IllegalStateException("Couldn't open database for " + uri); 24595fde670987a55d69442566dcbdb7830d5f1587c6Chih-Chung Chang } 2460ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen 2461ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen if (match == AUDIO_PLAYLISTS_ID || match == AUDIO_PLAYLISTS_ID_MEMBERS) { 2462ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen return playlistBulkInsert(db, uri, values); 2463e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } else if (match == MTP_OBJECT_REFERENCES) { 2464e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood int handle = Integer.parseInt(uri.getPathSegments().get(2)); 246510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen return setObjectReferences(helper, db, handle, values); 2466ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen } 2467ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen 2468702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.beginTransaction(); 2469702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int numInserted = 0; 2470702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 2471702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int len = values.length; 2472702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project for (int i = 0; i < len; i++) { 2473801ba04ac37ee06dccb8bf4081b29a162795e3a6Mike Lockwood if (values[i] != null) { 2474801ba04ac37ee06dccb8bf4081b29a162795e3a6Mike Lockwood insertInternal(uri, match, values[i]); 2475801ba04ac37ee06dccb8bf4081b29a162795e3a6Mike Lockwood } 2476702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2477702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project numInserted = len; 2478702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.setTransactionSuccessful(); 2479702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 2480702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.endTransaction(); 2481702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2482702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 2483702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return numInserted; 2484702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2485702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2486702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 2487801ba04ac37ee06dccb8bf4081b29a162795e3a6Mike Lockwood public Uri insert(Uri uri, ContentValues initialValues) { 24885d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood int match = URI_MATCHER.match(uri); 24895d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood Uri newUri = insertInternal(uri, match, initialValues); 24905d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood // do not signal notification for MTP objects. 24915d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood // we will signal instead after file transfer is successful. 2492e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood if (newUri != null && match != MTP_OBJECTS) { 2493702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 2494702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2495702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return newUri; 2496702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2497702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2498ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen private int playlistBulkInsert(SQLiteDatabase db, Uri uri, ContentValues values[]) { 2499ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen DatabaseUtils.InsertHelper helper = 2500ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen new DatabaseUtils.InsertHelper(db, "audio_playlists_map"); 25018b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen int audioidcolidx = helper.getColumnIndex(MediaStore.Audio.Playlists.Members.AUDIO_ID); 25028b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen int playlistididx = helper.getColumnIndex(Audio.Playlists.Members.PLAYLIST_ID); 25038b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen int playorderidx = helper.getColumnIndex(MediaStore.Audio.Playlists.Members.PLAY_ORDER); 25048b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen long playlistId = Long.parseLong(uri.getPathSegments().get(3)); 2505ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen 2506ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen db.beginTransaction(); 2507ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen int numInserted = 0; 2508ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen try { 2509ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen int len = values.length; 2510ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen for (int i = 0; i < len; i++) { 25118b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen helper.prepareForInsert(); 25128b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen // getting the raw Object and converting it long ourselves saves 25138b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen // an allocation (the alternative is ContentValues.getAsLong, which 25148b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen // returns a Long object) 25158b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen long audioid = ((Number) values[i].get( 25168b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen MediaStore.Audio.Playlists.Members.AUDIO_ID)).longValue(); 25178b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen helper.bind(audioidcolidx, audioid); 25188b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen helper.bind(playlistididx, playlistId); 25198b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen // convert to int ourselves to save an allocation. 25208b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen int playorder = ((Number) values[i].get( 25218b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen MediaStore.Audio.Playlists.Members.PLAY_ORDER)).intValue(); 25228b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen helper.bind(playorderidx, playorder); 25238b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen helper.execute(); 2524ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen } 2525ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen numInserted = len; 2526ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen db.setTransactionSuccessful(); 2527ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen } finally { 2528ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen db.endTransaction(); 2529ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen helper.close(); 2530ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen } 2531ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen getContext().getContentResolver().notifyChange(uri, null); 2532ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen return numInserted; 2533ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen } 2534ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen 253510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen private long insertDirectory(DatabaseHelper helper, SQLiteDatabase db, String path) { 253610af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen if (LOCAL_LOGV) Log.v(TAG, "inserting directory " + path); 2537ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood ContentValues values = new ContentValues(); 2538ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood values.put(FileColumns.FORMAT, MtpConstants.FORMAT_ASSOCIATION); 2539ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood values.put(FileColumns.DATA, path); 254010af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen values.put(FileColumns.PARENT, getParent(helper, db, path)); 25419be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood values.put(FileColumns.STORAGE_ID, getStorageId(path)); 2542f2921d9af0a43c4be56a88990b55efe86fc7bb29Mike Lockwood File file = new File(path); 2543f2921d9af0a43c4be56a88990b55efe86fc7bb29Mike Lockwood if (file.exists()) { 2544f2921d9af0a43c4be56a88990b55efe86fc7bb29Mike Lockwood values.put(FileColumns.DATE_MODIFIED, file.lastModified() / 1000); 2545f2921d9af0a43c4be56a88990b55efe86fc7bb29Mike Lockwood } 254610af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumInserts++; 2547ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood long rowId = db.insert("files", FileColumns.DATE_MODIFIED, values); 2548ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood sendObjectAdded(rowId); 2549ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood return rowId; 2550ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood } 2551ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood 255210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen private long getParent(DatabaseHelper helper, SQLiteDatabase db, String path) { 2553b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood int lastSlash = path.lastIndexOf('/'); 2554b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood if (lastSlash > 0) { 2555b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood String parentPath = path.substring(0, lastSlash); 25569be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood for (int i = 0; i < mExternalStoragePaths.length; i++) { 25579be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood if (parentPath.equals(mExternalStoragePaths[i])) { 25589be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood return 0; 25599be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood } 2560b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } 25617f36494e085c26c69cd5925e54028822025eff29Marco Nelissen Long cid = mDirectoryCache.get(parentPath); 25627f36494e085c26c69cd5925e54028822025eff29Marco Nelissen if (cid != null) { 25637f36494e085c26c69cd5925e54028822025eff29Marco Nelissen if (LOCAL_LOGV) Log.v(TAG, "Returning cached entry for " + parentPath); 25647f36494e085c26c69cd5925e54028822025eff29Marco Nelissen return cid; 25657f36494e085c26c69cd5925e54028822025eff29Marco Nelissen } 25667f36494e085c26c69cd5925e54028822025eff29Marco Nelissen 2567f7cc647081f0421c0247de275fa0754b29938c07Mike Lockwood // Use "LIKE" instead of "=" on case insensitive file systems so we do a 2568f7cc647081f0421c0247de275fa0754b29938c07Mike Lockwood // case insensitive match when looking for parent directory. 25697f36494e085c26c69cd5925e54028822025eff29Marco Nelissen // TODO: investigate whether a "nocase" constraint on the column and 25707f36494e085c26c69cd5925e54028822025eff29Marco Nelissen // using "=" would give the same result faster. 2571f7cc647081f0421c0247de275fa0754b29938c07Mike Lockwood String selection = (mCaseInsensitivePaths ? MediaStore.MediaColumns.DATA + " LIKE ?" 2572a9bb89771934314157dd26253195dc16bddc2cfaDongwon Kang // search only directories. 257310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen + " AND format=" + MtpConstants.FORMAT_ASSOCIATION 2574f7cc647081f0421c0247de275fa0754b29938c07Mike Lockwood : MediaStore.MediaColumns.DATA + "=?"); 2575b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood String [] selargs = { parentPath }; 257610af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumQueries++; 25777f36494e085c26c69cd5925e54028822025eff29Marco Nelissen Cursor c = db.query("files", sIdOnlyColumn, selection, selargs, null, null, null); 2578b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood try { 25797f36494e085c26c69cd5925e54028822025eff29Marco Nelissen long id; 2580b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood if (c == null || c.getCount() == 0) { 2581b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood // parent isn't in the database - so add it 258210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen id = insertDirectory(helper, db, parentPath); 25837f36494e085c26c69cd5925e54028822025eff29Marco Nelissen if (LOCAL_LOGV) Log.v(TAG, "Inserted " + parentPath); 2584b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } else { 2585b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood c.moveToFirst(); 25867f36494e085c26c69cd5925e54028822025eff29Marco Nelissen id = c.getLong(0); 25877f36494e085c26c69cd5925e54028822025eff29Marco Nelissen if (LOCAL_LOGV) Log.v(TAG, "Queried " + parentPath); 2588b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } 25897f36494e085c26c69cd5925e54028822025eff29Marco Nelissen mDirectoryCache.put(parentPath, id); 25907f36494e085c26c69cd5925e54028822025eff29Marco Nelissen return id; 2591b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } finally { 2592b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood if (c != null) c.close(); 2593b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } 2594b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } else { 2595b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood return 0; 2596b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } 2597b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } 2598b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 25999be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood private int getStorageId(String path) { 26009be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood for (int i = 0; i < mExternalStoragePaths.length; i++) { 26019be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood String test = mExternalStoragePaths[i]; 26029be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood if (path.startsWith(test)) { 26039be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood int length = test.length(); 26049be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood if (path.length() == length || path.charAt(length) == '/') { 26059be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood return MtpStorage.getStorageId(i); 26069be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood } 26079be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood } 26089be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood } 26099be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood // default to primary storage 26109be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood return MtpStorage.getStorageId(0); 26119be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood } 26129be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood 261310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen private long insertFile(DatabaseHelper helper, Uri uri, ContentValues initialValues, int mediaType, 2614afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood boolean notify) { 261510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen SQLiteDatabase db = helper.getWritableDatabase(); 2616afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood ContentValues values = null; 2617afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 2618afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood switch (mediaType) { 2619afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood case FileColumns.MEDIA_TYPE_IMAGE: { 262010af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen values = ensureFile(helper.mInternal, initialValues, ".jpg", "DCIM/Camera"); 2621afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 2622afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values.put(MediaStore.MediaColumns.DATE_ADDED, System.currentTimeMillis() / 1000); 2623afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood String data = values.getAsString(MediaColumns.DATA); 2624afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (! values.containsKey(MediaColumns.DISPLAY_NAME)) { 2625afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood computeDisplayName(data, values); 2626afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2627afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood computeTakenTime(values); 2628afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood break; 2629afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2630afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 2631afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood case FileColumns.MEDIA_TYPE_AUDIO: { 2632afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // SQLite Views are read-only, so we need to deconstruct this 2633afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // insert and do inserts into the underlying tables. 2634afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // If doing this here turns out to be a performance bottleneck, 2635afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // consider moving this to native code and using triggers on 2636afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // the view. 2637afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values = new ContentValues(initialValues); 2638afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 26392658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen String albumartist = values.getAsString(MediaStore.Audio.Media.ALBUM_ARTIST); 26402658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen String compilation = values.getAsString(MediaStore.Audio.Media.COMPILATION); 26412658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen values.remove(MediaStore.Audio.Media.COMPILATION); 26422658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen 2643afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // Insert the artist into the artist table and remove it from 2644afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // the input values 2645afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood Object so = values.get("artist"); 2646afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood String s = (so == null ? "" : so.toString()); 2647afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values.remove("artist"); 2648afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood long artistRowId; 264910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen HashMap<String, Long> artistCache = helper.mArtistCache; 2650801ba04ac37ee06dccb8bf4081b29a162795e3a6Mike Lockwood String path = values.getAsString(MediaStore.MediaColumns.DATA); 2651afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood synchronized(artistCache) { 2652afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood Long temp = artistCache.get(s); 2653afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (temp == null) { 265410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen artistRowId = getKeyIdForName(helper, db, 265510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen "artists", "artist_key", "artist", 2656afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood s, s, path, 0, null, artistCache, uri); 2657afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } else { 2658afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood artistRowId = temp.longValue(); 2659afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2660afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2661afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood String artist = s; 2662afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 2663afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // Do the same for the album field 2664afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood so = values.get("album"); 2665afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood s = (so == null ? "" : so.toString()); 2666afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values.remove("album"); 2667afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood long albumRowId; 266810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen HashMap<String, Long> albumCache = helper.mAlbumCache; 2669afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood synchronized(albumCache) { 26702658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen int albumhash = 0; 26712658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen if (albumartist != null) { 26722658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen albumhash = albumartist.hashCode(); 26732658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen } else if (compilation != null && compilation.equals("1")) { 26742658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen // nothing to do, hash already set 26752658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen } else { 26762658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen albumhash = path.substring(0, path.lastIndexOf('/')).hashCode(); 26772658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen } 2678afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood String cacheName = s + albumhash; 2679afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood Long temp = albumCache.get(cacheName); 2680afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (temp == null) { 268110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen albumRowId = getKeyIdForName(helper, db, 268210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen "albums", "album_key", "album", 2683afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood s, cacheName, path, albumhash, artist, albumCache, uri); 2684afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } else { 2685afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood albumRowId = temp; 2686afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2687afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 26885d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood 2689afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values.put("artist_id", Integer.toString((int)artistRowId)); 2690afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values.put("album_id", Integer.toString((int)albumRowId)); 2691afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood so = values.getAsString("title"); 2692afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood s = (so == null ? "" : so.toString()); 2693afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values.put("title_key", MediaStore.Audio.keyFor(s)); 2694afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // do a final trim of the title, in case it started with the special 2695afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // "sort first" character (ascii \001) 2696afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values.remove("title"); 2697afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values.put("title", s.trim()); 2698b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 2699801ba04ac37ee06dccb8bf4081b29a162795e3a6Mike Lockwood computeDisplayName(values.getAsString(MediaStore.MediaColumns.DATA), values); 2700afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood break; 2701afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2702afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 2703afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood case FileColumns.MEDIA_TYPE_VIDEO: { 270410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen values = ensureFile(helper.mInternal, initialValues, ".3gp", "video"); 2705801ba04ac37ee06dccb8bf4081b29a162795e3a6Mike Lockwood String data = values.getAsString(MediaStore.MediaColumns.DATA); 2706afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood computeDisplayName(data, values); 2707afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood computeTakenTime(values); 2708afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood break; 2709afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2710afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2711afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 2712afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (values == null) { 2713afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values = new ContentValues(initialValues); 2714afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2715fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood // compute bucket_id and bucket_display_name for all files 2716afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood String path = values.getAsString(MediaStore.MediaColumns.DATA); 2717fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood if (path != null) { 2718fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood computeBucketValues(path, values); 2719fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood } 2720fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood values.put(MediaStore.MediaColumns.DATE_ADDED, System.currentTimeMillis() / 1000); 2721afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 2722afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood long rowId = 0; 2723afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood Integer i = values.getAsInteger( 2724afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood MediaStore.MediaColumns.MEDIA_SCANNER_NEW_OBJECT_ID); 2725afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (i != null) { 2726afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood rowId = i.intValue(); 2727afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values = new ContentValues(values); 2728afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values.remove(MediaStore.MediaColumns.MEDIA_SCANNER_NEW_OBJECT_ID); 2729afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2730afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 2731afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood String title = values.getAsString(MediaStore.MediaColumns.TITLE); 27323572ac7fc911cda5e4ac60af9455820a7ddf6593Marco Nelissen if (title == null && path != null) { 2733c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood title = MediaFile.getFileTitle(path); 2734c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood } 2735c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood values.put(FileColumns.TITLE, title); 2736c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood 2737afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood String mimeType = values.getAsString(MediaStore.MediaColumns.MIME_TYPE); 2738afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood Integer formatObject = values.getAsInteger(FileColumns.FORMAT); 2739c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood int format = (formatObject == null ? 0 : formatObject.intValue()); 2740c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood if (format == 0) { 274163b4ed85f500e23297ad5eb530318e06b9ab2289Dongwon Kang if (TextUtils.isEmpty(path)) { 2742c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood // special case device created playlists 2743afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (mediaType == FileColumns.MEDIA_TYPE_PLAYLIST) { 2744c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood values.put(FileColumns.FORMAT, MtpConstants.FORMAT_ABSTRACT_AV_PLAYLIST); 2745c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood // create a file path for the benefit of MTP 27469be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood path = mExternalStoragePaths[0] 2747afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + "/Playlists/" + values.getAsString(Audio.Playlists.NAME); 2748c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood values.put(MediaStore.MediaColumns.DATA, path); 274910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen values.put(FileColumns.PARENT, getParent(helper, db, path)); 2750c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood } else { 275163b4ed85f500e23297ad5eb530318e06b9ab2289Dongwon Kang Log.e(TAG, "path is empty in insertFile()"); 2752c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood } 2753c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood } else { 2754c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood format = MediaFile.getFormatCode(path, mimeType); 2755c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood } 2756c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood } 2757c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood if (format != 0) { 2758c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood values.put(FileColumns.FORMAT, format); 2759c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood if (mimeType == null) { 2760c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood mimeType = MediaFile.getMimeTypeForFormatCode(format); 2761c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood } 2762c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood } 2763c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood 2764801ba04ac37ee06dccb8bf4081b29a162795e3a6Mike Lockwood if (mimeType == null && path != null) { 2765c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood mimeType = MediaFile.getMimeTypeForFile(path); 2766c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood } 2767c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood if (mimeType != null) { 2768c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood values.put(FileColumns.MIME_TYPE, mimeType); 2769afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 2770f1f6a9e343033de33fc748f659b9221f8d5b06e1Mike Lockwood if (mediaType == FileColumns.MEDIA_TYPE_NONE && !MediaScanner.isNoMediaPath(path)) { 2771afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood int fileType = MediaFile.getFileTypeForMimeType(mimeType); 2772afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (MediaFile.isAudioFileType(fileType)) { 2773afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood mediaType = FileColumns.MEDIA_TYPE_AUDIO; 2774afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } else if (MediaFile.isVideoFileType(fileType)) { 2775afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood mediaType = FileColumns.MEDIA_TYPE_VIDEO; 2776afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } else if (MediaFile.isImageFileType(fileType)) { 2777afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood mediaType = FileColumns.MEDIA_TYPE_IMAGE; 2778afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } else if (MediaFile.isPlayListFileType(fileType)) { 2779afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood mediaType = FileColumns.MEDIA_TYPE_PLAYLIST; 2780afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2781afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2782c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood } 2783afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values.put(FileColumns.MEDIA_TYPE, mediaType); 2784c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood 2785afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (rowId == 0) { 2786afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (mediaType == FileColumns.MEDIA_TYPE_PLAYLIST) { 27873572ac7fc911cda5e4ac60af9455820a7ddf6593Marco Nelissen String name = values.getAsString(Audio.Playlists.NAME); 2788282dc90a0e201d992cdd0d0176028da6a565f9d5Mike Lockwood if (name == null && path == null) { 2789282dc90a0e201d992cdd0d0176028da6a565f9d5Mike Lockwood // MediaScanner will compute the name from the path if we have one 2790afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood throw new IllegalArgumentException( 2791282dc90a0e201d992cdd0d0176028da6a565f9d5Mike Lockwood "no name was provided when inserting abstract playlist"); 2792afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2793afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } else { 2794a36cfaef630ef5df7bef80b25f6bd493d040c7e4Brian Muramatsu if (path == null) { 2795afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // path might be null for playlists created on the device 2796afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // or transfered via MTP 2797afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood throw new IllegalArgumentException( 2798afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "no path was provided when inserting new file"); 2799afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2800e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2801b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 2802f2921d9af0a43c4be56a88990b55efe86fc7bb29Mike Lockwood // make sure modification date and size are set 2803f2921d9af0a43c4be56a88990b55efe86fc7bb29Mike Lockwood if (path != null) { 2804f2921d9af0a43c4be56a88990b55efe86fc7bb29Mike Lockwood File file = new File(path); 2805f2921d9af0a43c4be56a88990b55efe86fc7bb29Mike Lockwood if (file.exists()) { 2806f2921d9af0a43c4be56a88990b55efe86fc7bb29Mike Lockwood values.put(FileColumns.DATE_MODIFIED, file.lastModified() / 1000); 280716dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood values.put(FileColumns.SIZE, file.length()); 2808e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 28095d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood } 2810b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 2811afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood Long parent = values.getAsLong(FileColumns.PARENT); 28125d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood if (parent == null) { 2813e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (path != null) { 281410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen long parentId = getParent(helper, db, path); 281516dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood values.put(FileColumns.PARENT, parentId); 2816e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 28179be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood } 28189be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood Integer storage = values.getAsInteger(FileColumns.STORAGE_ID); 28199be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood if (storage == null) { 28209be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood int storageId = getStorageId(path); 28219be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood values.put(FileColumns.STORAGE_ID, storageId); 28225d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood } 2823b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 282410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumInserts++; 2825afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood rowId = db.insert("files", FileColumns.DATE_MODIFIED, values); 2826afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (LOCAL_LOGV) Log.v(TAG, "insertFile: values=" + values + " returned: " + rowId); 2827afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 282810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen if (rowId != -1 && notify) { 2829afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood sendObjectAdded(rowId); 2830afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 28315d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood } else { 283210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumUpdates++; 283316dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood db.update("files", values, FileColumns._ID + "=?", 2834afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood new String[] { Long.toString(rowId) }); 28355d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood } 2836afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 2837afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood return rowId; 28381717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood } 28391717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood 284010af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen private Cursor getObjectReferences(DatabaseHelper helper, SQLiteDatabase db, int handle) { 284110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumQueries++; 284210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen Cursor c = db.query("files", mMediaTableColumns, "_id=?", 2843e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood new String[] { Integer.toString(handle) }, 2844e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood null, null, null); 2845e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood try { 2846e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (c != null && c.moveToNext()) { 2847afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood long playlistId = c.getLong(0); 2848afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood int mediaType = c.getInt(1); 2849afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (mediaType != FileColumns.MEDIA_TYPE_PLAYLIST) { 2850e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood // we only support object references for playlist objects 2851e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood return null; 2852e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 285310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumQueries++; 2854e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood return db.rawQuery(OBJECT_REFERENCES_QUERY, 2855afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood new String[] { Long.toString(playlistId) } ); 2856e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2857e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } finally { 2858e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (c != null) { 2859e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood c.close(); 2860e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2861e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2862e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood return null; 2863e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2864e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood 286510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen private int setObjectReferences(DatabaseHelper helper, SQLiteDatabase db, 286610af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen int handle, ContentValues values[]) { 2867e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood // first look up the media table and media ID for the object 2868e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood long playlistId = 0; 286910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumQueries++; 287016dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood Cursor c = db.query("files", mMediaTableColumns, "_id=?", 2871e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood new String[] { Integer.toString(handle) }, 2872e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood null, null, null); 2873e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood try { 2874e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (c != null && c.moveToNext()) { 2875afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood int mediaType = c.getInt(1); 2876afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (mediaType != FileColumns.MEDIA_TYPE_PLAYLIST) { 2877e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood // we only support object references for playlist objects 2878e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood return 0; 2879e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2880afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood playlistId = c.getLong(0); 2881e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2882e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } finally { 2883e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (c != null) { 2884e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood c.close(); 2885e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2886e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2887e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (playlistId == 0) { 2888e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood return 0; 2889e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2890e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood 2891e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood // next delete any existing entries 289210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumDeletes++; 289310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen db.delete("audio_playlists_map", "playlist_id=?", 2894e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood new String[] { Long.toString(playlistId) }); 2895e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood 2896e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood // finally add the new entries 2897e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood int count = values.length; 2898e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood int added = 0; 2899e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood ContentValues[] valuesList = new ContentValues[count]; 2900e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood for (int i = 0; i < count; i++) { 2901e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood // convert object ID to audio ID 2902e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood long audioId = 0; 2903e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood long objectId = values[i].getAsLong(MediaStore.MediaColumns._ID); 290410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumQueries++; 290516dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood c = db.query("files", mMediaTableColumns, "_id=?", 2906e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood new String[] { Long.toString(objectId) }, 2907e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood null, null, null); 2908e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood try { 2909e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (c != null && c.moveToNext()) { 2910afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood int mediaType = c.getInt(1); 291150d8650456d93e2107b9163e119c2eb9de73f804Mike Lockwood if (mediaType != FileColumns.MEDIA_TYPE_AUDIO) { 2912e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood // we only allow audio files in playlists, so skip 2913e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood continue; 2914e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2915afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood audioId = c.getLong(0); 2916e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2917e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } finally { 2918e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (c != null) { 2919e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood c.close(); 2920e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2921e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2922e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (audioId != 0) { 2923e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood ContentValues v = new ContentValues(); 2924e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood v.put(MediaStore.Audio.Playlists.Members.PLAYLIST_ID, playlistId); 2925e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood v.put(MediaStore.Audio.Playlists.Members.AUDIO_ID, audioId); 2926a08bc533a5f7bf9aea49b25a549b4f5b3c14f47dMike Lockwood v.put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, added); 2927a08bc533a5f7bf9aea49b25a549b4f5b3c14f47dMike Lockwood valuesList[added++] = v; 2928e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2929e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2930e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (added < count) { 2931e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood // we weren't able to find everything on the list, so lets resize the array 2932e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood // and pass what we have. 2933e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood ContentValues[] newValues = new ContentValues[added]; 2934e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood System.arraycopy(valuesList, 0, newValues, 0, added); 2935e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood valuesList = newValues; 2936e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2937e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood return playlistBulkInsert(db, 2938e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood Audio.Playlists.Members.getContentUri(EXTERNAL_VOLUME, playlistId), 2939e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood valuesList); 2940e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2941e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood 2942b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood private static final String[] GENRE_LOOKUP_PROJECTION = new String[] { 2943b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood Audio.Genres._ID, // 0 2944b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood Audio.Genres.NAME, // 1 2945b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood }; 2946b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood 2947b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood private void updateGenre(long rowId, String genre) { 2948b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood Uri uri = null; 2949b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood Cursor cursor = null; 2950b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood Uri genresUri = MediaStore.Audio.Genres.getContentUri("external"); 2951b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood try { 2952b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood // see if the genre already exists 2953b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood cursor = query(genresUri, GENRE_LOOKUP_PROJECTION, MediaStore.Audio.Genres.NAME + "=?", 2954b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood new String[] { genre }, null); 2955b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood if (cursor == null || cursor.getCount() == 0) { 2956b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood // genre does not exist, so create the genre in the genre table 2957b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood ContentValues values = new ContentValues(); 2958b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood values.put(MediaStore.Audio.Genres.NAME, genre); 2959b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood uri = insert(genresUri, values); 2960b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood } else { 2961b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood // genre already exists, so compute its Uri 2962b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood cursor.moveToNext(); 2963b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood uri = ContentUris.withAppendedId(genresUri, cursor.getLong(0)); 2964b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood } 2965b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood if (uri != null) { 2966b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood uri = Uri.withAppendedPath(uri, MediaStore.Audio.Genres.Members.CONTENT_DIRECTORY); 2967b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood } 2968b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood } finally { 2969b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood // release the cursor if it exists 2970b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood if (cursor != null) { 2971b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood cursor.close(); 2972b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood } 2973b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood } 2974b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood 2975b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood if (uri != null) { 2976b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood // add entry to audio_genre_map 2977b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood ContentValues values = new ContentValues(); 2978b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood values.put(MediaStore.Audio.Genres.Members.AUDIO_ID, Long.valueOf(rowId)); 2979b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood insert(uri, values); 2980b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood } 2981b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood } 2982b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood 29835d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood private Uri insertInternal(Uri uri, int match, ContentValues initialValues) { 2984702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long rowId; 2985702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2986d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood if (LOCAL_LOGV) Log.v(TAG, "insertInternal: "+uri+", initValues="+initialValues); 2987702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // handle MEDIA_SCANNER before calling getDatabaseForUri() 2988702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (match == MEDIA_SCANNER) { 2989bc442ef681710cca3d8eb1a57d6e81471c9987c0Mike Lockwood mMediaScannerVolume = initialValues.getAsString(MediaStore.MEDIA_SCANNER_VOLUME); 299010af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen DatabaseHelper database = getDatabaseForUri( 299110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen Uri.parse("content://media/" + mMediaScannerVolume + "/audio")); 299210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen if (database == null) { 299310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen Log.w(TAG, "no database for scanned volume " + mMediaScannerVolume); 299410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen } else { 299510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen database.mScanStartTime = SystemClock.currentTimeMicro(); 299610af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen } 2997702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return MediaStore.getMediaScannerUri(); 2998702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2999702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3000b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood String genre = null; 3001b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood if (initialValues != null) { 3002b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood genre = initialValues.getAsString(Audio.AudioColumns.GENRE); 3003b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood initialValues.remove(Audio.AudioColumns.GENRE); 3004b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood } 3005b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood 3006702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Uri newUri = null; 300710af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen DatabaseHelper helper = getDatabaseForUri(uri); 300810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen if (helper == null && match != VOLUMES && match != MTP_CONNECTED) { 3009702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException( 3010702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Unknown URI: " + uri); 3011702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 301210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen 3013819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood SQLiteDatabase db = ((match == VOLUMES || match == MTP_CONNECTED) ? null 301410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen : helper.getWritableDatabase()); 3015702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3016702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (match) { 3017702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA: { 301810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen rowId = insertFile(helper, uri, initialValues, FileColumns.MEDIA_TYPE_IMAGE, true); 3019702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 3020702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId( 3021702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Images.Media.getContentUri(uri.getPathSegments().get(0)), rowId); 3022702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3023702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3024702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3025702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3026b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // This will be triggered by requestMediaThumbnail (see getThumbnailUri) 3027702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_THUMBNAILS: { 302810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen ContentValues values = ensureFile(helper.mInternal, initialValues, ".jpg", 3029b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "DCIM/.thumbnails"); 303010af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumInserts++; 3031702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert("thumbnails", "name", values); 3032702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 3033702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(Images.Thumbnails. 3034702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContentUri(uri.getPathSegments().get(0)), rowId); 3035702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3036702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3037702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3038702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3039b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // This is currently only used by MICRO_KIND video thumbnail (see getThumbnailUri) 3040b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case VIDEO_THUMBNAILS: { 304110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen ContentValues values = ensureFile(helper.mInternal, initialValues, ".jpg", 3042b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "DCIM/.thumbnails"); 304310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumInserts++; 3044b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen rowId = db.insert("videothumbnails", "name", values); 3045b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (rowId > 0) { 3046b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen newUri = ContentUris.withAppendedId(Video.Thumbnails. 3047b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen getContentUri(uri.getPathSegments().get(0)), rowId); 3048b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 3049b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen break; 3050b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 3051b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 3052702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA: { 305310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen rowId = insertFile(helper, uri, initialValues, FileColumns.MEDIA_TYPE_AUDIO, true); 3054702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 3055702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(Audio.Media.getContentUri(uri.getPathSegments().get(0)), rowId); 3056b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood if (genre != null) { 3057b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood updateGenre(rowId, genre); 3058b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood } 3059702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3060702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3061702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3062702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3063702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES: { 3064702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Long audioId = Long.parseLong(uri.getPathSegments().get(2)); 3065bc442ef681710cca3d8eb1a57d6e81471c9987c0Mike Lockwood ContentValues values = new ContentValues(initialValues); 3066702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(Audio.Genres.Members.AUDIO_ID, audioId); 306710af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumInserts++; 3068ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen rowId = db.insert("audio_genres_map", "genre_id", values); 3069702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 3070702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(uri, rowId); 3071702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3072702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3073702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3074702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3075702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS: { 3076702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Long audioId = Long.parseLong(uri.getPathSegments().get(2)); 3077bc442ef681710cca3d8eb1a57d6e81471c9987c0Mike Lockwood ContentValues values = new ContentValues(initialValues); 3078702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(Audio.Playlists.Members.AUDIO_ID, audioId); 307910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumInserts++; 3080702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert("audio_playlists_map", "playlist_id", 3081702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values); 3082702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 3083702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(uri, rowId); 3084702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3085702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3086702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3087702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3088702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES: { 308910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumInserts++; 3090bc442ef681710cca3d8eb1a57d6e81471c9987c0Mike Lockwood rowId = db.insert("audio_genres", "audio_id", initialValues); 3091702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 3092702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(Audio.Genres.getContentUri(uri.getPathSegments().get(0)), rowId); 3093702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3094702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3095702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3096702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3097702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID_MEMBERS: { 3098702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Long genreId = Long.parseLong(uri.getPathSegments().get(3)); 3099bc442ef681710cca3d8eb1a57d6e81471c9987c0Mike Lockwood ContentValues values = new ContentValues(initialValues); 3100702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(Audio.Genres.Members.GENRE_ID, genreId); 310110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumInserts++; 3102702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert("audio_genres_map", "genre_id", values); 3103702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 3104702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(uri, rowId); 3105702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3106702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3107702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3108702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3109702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS: { 3110bc442ef681710cca3d8eb1a57d6e81471c9987c0Mike Lockwood ContentValues values = new ContentValues(initialValues); 3111702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(MediaStore.Audio.Playlists.DATE_ADDED, System.currentTimeMillis() / 1000); 311210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen rowId = insertFile(helper, uri, values, FileColumns.MEDIA_TYPE_PLAYLIST, true); 3113702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 3114702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(Audio.Playlists.getContentUri(uri.getPathSegments().get(0)), rowId); 3115702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3116702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3117702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3118702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3119702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID: 3120702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS: { 3121702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Long playlistId = Long.parseLong(uri.getPathSegments().get(3)); 3122bc442ef681710cca3d8eb1a57d6e81471c9987c0Mike Lockwood ContentValues values = new ContentValues(initialValues); 3123702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(Audio.Playlists.Members.PLAYLIST_ID, playlistId); 312410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumInserts++; 3125ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen rowId = db.insert("audio_playlists_map", "playlist_id", values); 3126702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 3127702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(uri, rowId); 3128702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3129702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3130702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3131702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3132702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA: { 313310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen rowId = insertFile(helper, uri, initialValues, FileColumns.MEDIA_TYPE_VIDEO, true); 3134702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 3135b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen newUri = ContentUris.withAppendedId(Video.Media.getContentUri( 3136b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen uri.getPathSegments().get(0)), rowId); 3137702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3138702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3139702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3140702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3141c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood case AUDIO_ALBUMART: { 314210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen if (helper.mInternal) { 3143702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException("no internal album art allowed"); 3144702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3145bc442ef681710cca3d8eb1a57d6e81471c9987c0Mike Lockwood ContentValues values = null; 3146702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 3147bc442ef681710cca3d8eb1a57d6e81471c9987c0Mike Lockwood values = ensureFile(false, initialValues, "", ALBUM_THUMB_FOLDER); 3148702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } catch (IllegalStateException ex) { 3149702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // probably no more room to store albumthumbs 3150bc442ef681710cca3d8eb1a57d6e81471c9987c0Mike Lockwood values = initialValues; 3151702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 315210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumInserts++; 3153801ba04ac37ee06dccb8bf4081b29a162795e3a6Mike Lockwood rowId = db.insert("album_art", MediaStore.MediaColumns.DATA, values); 3154702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 3155702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(uri, rowId); 3156702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3157702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3158c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood } 3159702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3160702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VOLUMES: 3161bc442ef681710cca3d8eb1a57d6e81471c9987c0Mike Lockwood return attachVolume(initialValues.getAsString("name")); 3162702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3163819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood case MTP_CONNECTED: 316434be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood synchronized (mMtpServiceConnection) { 316534be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood if (mMtpService == null) { 316634be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood Context context = getContext(); 316734be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood // MTP is connected, so grab a connection to MtpService 316834be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood context.bindService(new Intent(context, MtpService.class), 316934be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood mMtpServiceConnection, Context.BIND_AUTO_CREATE); 317034be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood } 317134be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood } 3172819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood break; 3173819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood 3174afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood case FILES: 317510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen rowId = insertFile(helper, uri, initialValues, 3176bc442ef681710cca3d8eb1a57d6e81471c9987c0Mike Lockwood FileColumns.MEDIA_TYPE_NONE, true); 3177fc824ed365b03ae272a3241b202367b1bdec18bcMike Lockwood if (rowId > 0) { 3178fc824ed365b03ae272a3241b202367b1bdec18bcMike Lockwood newUri = Files.getContentUri(uri.getPathSegments().get(0), rowId); 317910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen if (initialValues.getAsInteger(MediaStore.Files.FileColumns.FORMAT) 318010af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen == MtpConstants.FORMAT_ASSOCIATION) { 318110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen mDirectoryCache.put( 318210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen initialValues.getAsString(MediaStore.MediaColumns.DATA), rowId); 318310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen } 3184fc824ed365b03ae272a3241b202367b1bdec18bcMike Lockwood } 3185fc824ed365b03ae272a3241b202367b1bdec18bcMike Lockwood break; 3186fc824ed365b03ae272a3241b202367b1bdec18bcMike Lockwood 3187e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood case MTP_OBJECTS: 3188afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // don't send a notification if the insert originated from MTP 318910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen rowId = insertFile(helper, uri, initialValues, 3190bc442ef681710cca3d8eb1a57d6e81471c9987c0Mike Lockwood FileColumns.MEDIA_TYPE_NONE, false); 3191afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (rowId > 0) { 3192afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood newUri = Files.getMtpObjectsUri(uri.getPathSegments().get(0), rowId); 31935d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood } 31945d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood break; 31955d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood 3196702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project default: 3197702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException("Invalid URI " + uri); 3198702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3199702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3200702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return newUri; 3201702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3202702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3203cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen @Override 3204cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) 3205cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen throws OperationApplicationException { 3206cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen 3207cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen // The operations array provides no overall information about the URI(s) being operated 3208cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen // on, so begin a transaction for ALL of the databases. 3209cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen DatabaseHelper ihelper = getDatabaseForUri(MediaStore.Audio.Media.INTERNAL_CONTENT_URI); 3210cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen DatabaseHelper ehelper = getDatabaseForUri(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI); 3211cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen SQLiteDatabase idb = ihelper.getWritableDatabase(); 3212cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen idb.beginTransaction(); 3213cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen SQLiteDatabase edb = null; 3214cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen if (ehelper != null) { 3215cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen edb = ehelper.getWritableDatabase(); 3216cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen edb.beginTransaction(); 3217cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen } 3218cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen try { 3219cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen ContentProviderResult[] result = super.applyBatch(operations); 3220cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen idb.setTransactionSuccessful(); 3221cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen if (edb != null) { 3222cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen edb.setTransactionSuccessful(); 3223cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen } 3224cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen // Rather than sending targeted change notifications for every Uri 3225cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen // affected by the batch operation, just invalidate the entire internal 3226cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen // and external name space. 3227cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen ContentResolver res = getContext().getContentResolver(); 3228cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen res.notifyChange(Uri.parse("content://media/"), null); 3229cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen return result; 3230cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen } finally { 3231cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen idb.endTransaction(); 3232cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen if (edb != null) { 3233cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen edb.endTransaction(); 3234cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen } 3235cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen } 3236cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen } 3237cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen 3238cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen 32399299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen private MediaThumbRequest requestMediaThumbnail(String path, Uri uri, int priority, long magic) { 3240b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen synchronized (mMediaThumbQueue) { 3241e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen MediaThumbRequest req = null; 3242e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen try { 3243e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen req = new MediaThumbRequest( 32449299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen getContext().getContentResolver(), path, uri, priority, magic); 3245e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen mMediaThumbQueue.add(req); 3246e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen // Trigger the handler. 3247e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen Message msg = mThumbHandler.obtainMessage(IMAGE_THUMB); 3248e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen msg.sendToTarget(); 3249e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen } catch (Throwable t) { 3250e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen Log.w(TAG, t); 3251e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen } 3252b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return req; 3253b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 3254b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 3255b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 3256702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private String generateFileName(boolean internal, String preferredExtension, String directoryName) 3257702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project { 3258702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // create a random file 3259702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String name = String.valueOf(System.currentTimeMillis()); 3260702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3261702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (internal) { 3262702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException("Writing to internal storage is not supported."); 3263702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project// return Environment.getDataDirectory() 3264702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project// + "/" + directoryName + "/" + name + preferredExtension; 3265702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 32669be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood return mExternalStoragePaths[0] + "/" + directoryName + "/" + name + preferredExtension; 3267702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3268702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3269702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3270702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private boolean ensureFileExists(String path) { 3271702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File file = new File(path); 3272702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (file.exists()) { 3273702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return true; 3274702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 3275702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // we will not attempt to create the first directory in the path 3276702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // (for example, do not create /sdcard if the SD card is not mounted) 3277702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int secondSlash = path.indexOf('/', 1); 3278702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (secondSlash < 1) return false; 3279702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String directoryPath = path.substring(0, secondSlash); 3280702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File directory = new File(directoryPath); 3281702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!directory.exists()) 3282702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return false; 328317ad80b32f839ccddac3911799ff732d1ca3a006Mike Lockwood file.getParentFile().mkdirs(); 3284702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 328517ad80b32f839ccddac3911799ff732d1ca3a006Mike Lockwood return file.createNewFile(); 3286702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } catch(IOException ioe) { 3287702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Log.e(TAG, "File creation failed", ioe); 3288702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3289702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return false; 3290702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3291702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3292702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3293702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final class GetTableAndWhereOutParameter { 3294702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public String table; 3295702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public String where; 3296702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3297702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3298702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project static final GetTableAndWhereOutParameter sGetTableAndWhereParam = 3299702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project new GetTableAndWhereOutParameter(); 3300702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3301702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private void getTableAndWhere(Uri uri, int match, String userWhere, 3302702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project GetTableAndWhereOutParameter out) { 3303702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String where = null; 3304702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (match) { 33059f02f449f6951b15bb9daaa3fc6e1d648b36b08aGoodwin case IMAGES_MEDIA: 3306afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood out.table = "files"; 3307afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood where = FileColumns.MEDIA_TYPE + "=" + FileColumns.MEDIA_TYPE_IMAGE; 33089f02f449f6951b15bb9daaa3fc6e1d648b36b08aGoodwin break; 33099f02f449f6951b15bb9daaa3fc6e1d648b36b08aGoodwin 3310702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA_ID: 3311afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood out.table = "files"; 3312702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "_id = " + uri.getPathSegments().get(3); 3313702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3314702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3315b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case IMAGES_THUMBNAILS_ID: 3316b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen where = "_id=" + uri.getPathSegments().get(3); 3317b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case IMAGES_THUMBNAILS: 3318b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen out.table = "thumbnails"; 3319b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen break; 3320b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 3321702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA: 3322afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood out.table = "files"; 3323afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood where = FileColumns.MEDIA_TYPE + "=" + FileColumns.MEDIA_TYPE_AUDIO; 3324702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3325702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3326702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID: 3327afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood out.table = "files"; 3328702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "_id=" + uri.getPathSegments().get(3); 3329702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3330702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3331702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES: 3332702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_genres"; 3333702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "audio_id=" + uri.getPathSegments().get(3); 3334702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3335702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3336702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES_ID: 3337702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_genres"; 3338702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "audio_id=" + uri.getPathSegments().get(3) + 3339702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " AND genre_id=" + uri.getPathSegments().get(5); 3340702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3341702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3342702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS: 3343702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_playlists"; 3344702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "audio_id=" + uri.getPathSegments().get(3); 3345702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3346702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3347702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS_ID: 3348702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_playlists"; 3349702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "audio_id=" + uri.getPathSegments().get(3) + 3350702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " AND playlists_id=" + uri.getPathSegments().get(5); 3351702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3352702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3353702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES: 3354702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_genres"; 3355702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3356702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3357702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID: 3358702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_genres"; 3359702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "_id=" + uri.getPathSegments().get(3); 3360702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3361702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3362702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID_MEMBERS: 3363702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_genres"; 3364702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "genre_id=" + uri.getPathSegments().get(3); 3365702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3366702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3367702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS: 3368afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood out.table = "files"; 3369afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood where = FileColumns.MEDIA_TYPE + "=" + FileColumns.MEDIA_TYPE_PLAYLIST; 3370702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3371702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3372702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID: 3373afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood out.table = "files"; 3374702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "_id=" + uri.getPathSegments().get(3); 3375702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3376702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3377702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS: 3378702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_playlists_map"; 3379702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "playlist_id=" + uri.getPathSegments().get(3); 3380702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3381702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3382702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS_ID: 3383702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_playlists_map"; 3384702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "playlist_id=" + uri.getPathSegments().get(3) + 3385702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " AND _id=" + uri.getPathSegments().get(5); 3386702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3387702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3388702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ALBUMART_ID: 3389702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "album_art"; 3390702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "album_id=" + uri.getPathSegments().get(3); 3391702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3392702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3393702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA: 3394afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood out.table = "files"; 3395afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood where = FileColumns.MEDIA_TYPE + "=" + FileColumns.MEDIA_TYPE_VIDEO; 3396702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3397702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3398702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA_ID: 3399afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood out.table = "files"; 3400702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "_id=" + uri.getPathSegments().get(3); 3401702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3402702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3403b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case VIDEO_THUMBNAILS_ID: 3404b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen where = "_id=" + uri.getPathSegments().get(3); 3405b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case VIDEO_THUMBNAILS: 3406b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen out.table = "videothumbnails"; 3407b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen break; 3408b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 340916dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood case FILES_ID: 3410e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood case MTP_OBJECTS_ID: 34111717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood where = "_id=" + uri.getPathSegments().get(2); 341216dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood case FILES: 3413e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood case MTP_OBJECTS: 341416dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood out.table = "files"; 34151717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood break; 34161717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood 3417702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project default: 3418702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException( 3419702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Unknown or unsupported URL: " + uri.toString()); 3420702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3421702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3422702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Add in the user requested WHERE clause, if needed 3423702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!TextUtils.isEmpty(userWhere)) { 3424702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!TextUtils.isEmpty(where)) { 3425702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.where = where + " AND (" + userWhere + ")"; 3426702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 3427702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.where = userWhere; 3428702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3429702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 3430702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.where = where; 3431702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3432702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3433702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3434702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 3435702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public int delete(Uri uri, String userWhere, String[] whereArgs) { 3436702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int count; 3437702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int match = URI_MATCHER.match(uri); 3438702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3439702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // handle MEDIA_SCANNER before calling getDatabaseForUri() 3440702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (match == MEDIA_SCANNER) { 3441702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (mMediaScannerVolume == null) { 3442702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return 0; 3443702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 344410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen DatabaseHelper database = getDatabaseForUri( 344510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen Uri.parse("content://media/" + mMediaScannerVolume + "/audio")); 344610af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen if (database == null) { 344710af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen Log.w(TAG, "no database for scanned volume " + mMediaScannerVolume); 344810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen } else { 344910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen database.mScanStopTime = SystemClock.currentTimeMicro(); 345010af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen } 3451702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mMediaScannerVolume = null; 3452702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return 1; 3453702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3454702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3455819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood if (match == VOLUMES_ID) { 3456819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood detachVolume(uri); 3457819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood count = 1; 3458819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood } else if (match == MTP_CONNECTED) { 345934be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood synchronized (mMtpServiceConnection) { 346034be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood if (mMtpService != null) { 346134be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood // MTP has disconnected, so release our connection to MtpService 346234be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood getContext().unbindService(mMtpServiceConnection); 346334be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood count = 1; 346434be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood // mMtpServiceConnection.onServiceDisconnected might not get called, 346534be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood // so set mMtpService = null here 346634be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood mMtpService = null; 346734be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood } else { 346834be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood count = 0; 346934be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood } 347034be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood } 3471819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood } else { 3472702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DatabaseHelper database = getDatabaseForUri(uri); 3473702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (database == null) { 3474702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException( 3475819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood "Unknown URI: " + uri + " match: " + match); 3476702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 347710af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen database.mNumDeletes++; 3478702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteDatabase db = database.getWritableDatabase(); 3479702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3480702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized (sGetTableAndWhereParam) { 3481702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getTableAndWhere(uri, match, userWhere, sGetTableAndWhereParam); 3482702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (match) { 348336339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood case MTP_OBJECTS: 3484e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood case MTP_OBJECTS_ID: 3485d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood try { 3486d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood // don't send objectRemoved event since this originated from MTP 3487d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood mDisableMtpObjectCallbacks = true; 348810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen database.mNumDeletes++; 348910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen count = db.delete("files", sGetTableAndWhereParam.where, whereArgs); 3490d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } finally { 3491d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood mDisableMtpObjectCallbacks = false; 3492d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 349336339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood break; 349478b2885edc406273d688536b0eadfea006b20662Marco Nelissen case AUDIO_GENRES_ID_MEMBERS: 349510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen database.mNumDeletes++; 349678b2885edc406273d688536b0eadfea006b20662Marco Nelissen count = db.delete("audio_genres_map", 349778b2885edc406273d688536b0eadfea006b20662Marco Nelissen sGetTableAndWhereParam.where, whereArgs); 349878b2885edc406273d688536b0eadfea006b20662Marco Nelissen break; 3499702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project default: 350010af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen database.mNumDeletes++; 3501702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count = db.delete(sGetTableAndWhereParam.table, 3502702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sGetTableAndWhereParam.where, whereArgs); 3503702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3504702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 35053631d46b679a64a16918698121916b60d7c86e97Mike Lockwood // Since there are multiple Uris that can refer to the same files 35063631d46b679a64a16918698121916b60d7c86e97Mike Lockwood // and deletes can affect other objects in storage (like subdirectories 35073631d46b679a64a16918698121916b60d7c86e97Mike Lockwood // or playlists) we will notify a change on the entire volume to make 35083631d46b679a64a16918698121916b60d7c86e97Mike Lockwood // sure no listeners miss the notification. 35093631d46b679a64a16918698121916b60d7c86e97Mike Lockwood String volume = uri.getPathSegments().get(0); 35103631d46b679a64a16918698121916b60d7c86e97Mike Lockwood Uri notifyUri = Uri.parse("content://" + MediaStore.AUTHORITY + "/" + volume); 35113631d46b679a64a16918698121916b60d7c86e97Mike Lockwood getContext().getContentResolver().notifyChange(notifyUri, null); 3512702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3513702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3514702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3515702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return count; 3516702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3517702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3518702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 3519702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public int update(Uri uri, ContentValues initialValues, String userWhere, 3520702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String[] whereArgs) { 3521702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int count; 3522b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // Log.v(TAG, "update for uri="+uri+", initValues="+initialValues); 3523702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int match = URI_MATCHER.match(uri); 352410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen DatabaseHelper helper = getDatabaseForUri(uri); 352510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen if (helper == null) { 3526702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException( 3527702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Unknown URI: " + uri); 3528702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 352910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumUpdates++; 353010af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen 353110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen SQLiteDatabase db = helper.getWritableDatabase(); 3532702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3533b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood String genre = null; 3534b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood if (initialValues != null) { 3535b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood genre = initialValues.getAsString(Audio.AudioColumns.GENRE); 3536b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood initialValues.remove(Audio.AudioColumns.GENRE); 3537b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood } 3538b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood 3539702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized (sGetTableAndWhereParam) { 3540702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getTableAndWhere(uri, match, userWhere, sGetTableAndWhereParam); 3541702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 35421d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood // special case renaming directories via MTP. 35431d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood // in this case we must update all paths in the database with 35441d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood // the directory name as a prefix 35451d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood if ((match == MTP_OBJECTS || match == MTP_OBJECTS_ID) 35461d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood && initialValues != null && initialValues.size() == 1) { 35471d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood String oldPath = null; 3548801ba04ac37ee06dccb8bf4081b29a162795e3a6Mike Lockwood String newPath = initialValues.getAsString(MediaStore.MediaColumns.DATA); 35497f36494e085c26c69cd5925e54028822025eff29Marco Nelissen mDirectoryCache.remove(newPath); 35501d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood // MtpDatabase will rename the directory first, so we test the new file name 35511d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood if (newPath != null && (new File(newPath)).isDirectory()) { 355210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumQueries++; 35531d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood Cursor cursor = db.query(sGetTableAndWhereParam.table, PATH_PROJECTION, 35541d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood userWhere, whereArgs, null, null, null); 35551d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood try { 35561d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood if (cursor != null && cursor.moveToNext()) { 35571d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood oldPath = cursor.getString(1); 35581d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood } 35591d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood } finally { 35601d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood if (cursor != null) cursor.close(); 35611d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood } 35621d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood if (oldPath != null) { 35637f36494e085c26c69cd5925e54028822025eff29Marco Nelissen mDirectoryCache.remove(oldPath); 35641d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood // first rename the row for the directory 356510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumUpdates++; 35661d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood count = db.update(sGetTableAndWhereParam.table, initialValues, 35671d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood sGetTableAndWhereParam.where, whereArgs); 35681d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood if (count > 0) { 35691d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood // then update the paths of any files and folders contained in the directory. 35702d114cff87e8cd61123dce29e87d469abae98f6cMike Lockwood Object[] bindArgs = new Object[] {oldPath + "/", newPath + "/"}; 357110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumUpdates++; 35722d114cff87e8cd61123dce29e87d469abae98f6cMike Lockwood db.execSQL("UPDATE files SET _data=REPLACE(_data, ?1, ?2);", bindArgs); 35731d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood } 35741d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood 35751d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood if (count > 0 && !db.inTransaction()) { 35761d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood getContext().getContentResolver().notifyChange(uri, null); 35771d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood } 35781d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood return count; 35791d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood } 35801d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood } 35811d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood } 35821d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood 3583702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (match) { 3584702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA: 3585702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID: 3586702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project { 3587702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(initialValues); 35882658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen String albumartist = values.getAsString(MediaStore.Audio.Media.ALBUM_ARTIST); 35892658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen String compilation = values.getAsString(MediaStore.Audio.Media.COMPILATION); 35902658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen values.remove(MediaStore.Audio.Media.COMPILATION); 359107656cccafca173c6ab54c681a69538dcf0516ddMarco Nelissen 3592702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Insert the artist into the artist table and remove it from 3593702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // the input values 3594a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen String artist = values.getAsString("artist"); 35956006570c27674c47fcea8e674832a715cfd653eaMarco Nelissen values.remove("artist"); 3596a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen if (artist != null) { 3597702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long artistRowId; 359810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen HashMap<String, Long> artistCache = helper.mArtistCache; 3599702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized(artistCache) { 3600a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen Long temp = artistCache.get(artist); 3601702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (temp == null) { 360210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen artistRowId = getKeyIdForName(helper, db, 360310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen "artists", "artist_key", "artist", 3604acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen artist, artist, null, 0, null, artistCache, uri); 3605702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 3606702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project artistRowId = temp.longValue(); 3607702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3608702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3609702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put("artist_id", Integer.toString((int)artistRowId)); 3610702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3611702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 361259948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // Do the same for the album field. 3613a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen String so = values.getAsString("album"); 36146006570c27674c47fcea8e674832a715cfd653eaMarco Nelissen values.remove("album"); 3615702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (so != null) { 3616801ba04ac37ee06dccb8bf4081b29a162795e3a6Mike Lockwood String path = values.getAsString(MediaStore.MediaColumns.DATA); 361759948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen int albumHash = 0; 36182658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen if (albumartist != null) { 36192658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen albumHash = albumartist.hashCode(); 36202658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen } else if (compilation != null && compilation.equals("1")) { 36212658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen // nothing to do, hash already set 362259948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen } else { 36239289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen if (path == null) { 36249289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen if (match == AUDIO_MEDIA) { 36259289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen Log.w(TAG, "Possible multi row album name update without" 36269289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen + " path could give wrong album key"); 36279289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen } else { 36289289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen //Log.w(TAG, "Specify path to avoid extra query"); 36299289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen Cursor c = query(uri, 36309289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen new String[] { MediaStore.Audio.Media.DATA}, 36319289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen null, null, null); 36329289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen if (c != null) { 36339289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen try { 36349289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen int numrows = c.getCount(); 36359289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen if (numrows == 1) { 36369289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen c.moveToFirst(); 36379289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen path = c.getString(0); 36389289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen } else { 36399289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen Log.e(TAG, "" + numrows + " rows for " + uri); 36409289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen } 36419289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen } finally { 36429289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen c.close(); 36439289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen } 36449289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen } 36459289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen } 36469289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen } 36479289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen if (path != null) { 36489289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen albumHash = path.substring(0, path.lastIndexOf('/')).hashCode(); 36499289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen } 365059948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen } 36512658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen 3652702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String s = so.toString(); 3653702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long albumRowId; 365410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen HashMap<String, Long> albumCache = helper.mAlbumCache; 3655702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized(albumCache) { 365659948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen String cacheName = s + albumHash; 365759948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen Long temp = albumCache.get(cacheName); 3658702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (temp == null) { 365910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen albumRowId = getKeyIdForName(helper, db, 366010af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen "albums", "album_key", "album", 3661a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen s, cacheName, path, albumHash, artist, albumCache, uri); 3662702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 3663702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project albumRowId = temp.longValue(); 3664702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3665702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3666702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put("album_id", Integer.toString((int)albumRowId)); 3667702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3668702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3669702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // don't allow the title_key field to be updated directly 3670702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.remove("title_key"); 3671702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // If the title field is modified, update the title_key 3672702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project so = values.getAsString("title"); 3673702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (so != null) { 3674702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String s = so.toString(); 3675702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put("title_key", MediaStore.Audio.keyFor(s)); 3676e96c1d9637e89b5f99c7002fd06f7f35a9164849Marco Nelissen // do a final trim of the title, in case it started with the special 3677e96c1d9637e89b5f99c7002fd06f7f35a9164849Marco Nelissen // "sort first" character (ascii \001) 3678e96c1d9637e89b5f99c7002fd06f7f35a9164849Marco Nelissen values.remove("title"); 3679e96c1d9637e89b5f99c7002fd06f7f35a9164849Marco Nelissen values.put("title", s.trim()); 3680702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3681702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 368210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumUpdates++; 3683afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood count = db.update(sGetTableAndWhereParam.table, values, 3684afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood sGetTableAndWhereParam.where, whereArgs); 3685b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood if (genre != null) { 3686b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood if (count == 1 && match == AUDIO_MEDIA_ID) { 3687b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood long rowId = Long.parseLong(uri.getPathSegments().get(3)); 3688b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood updateGenre(rowId, genre); 3689b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood } else { 3690b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood // can't handle genres for bulk update or for non-audio files 3691b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood Log.w(TAG, "ignoring genre in update: count = " 3692b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood + count + " match = " + match); 3693b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood } 3694b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood } 3695702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3696702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3697702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA: 3698702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA_ID: 3699702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA: 3700702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA_ID: 3701702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project { 3702702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(initialValues); 3703702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Don't allow bucket id or display name to be updated directly. 3704702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // The same names are used for both images and table columns, so 3705702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // we use the ImageColumns constants here. 3706702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.remove(ImageColumns.BUCKET_ID); 3707702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.remove(ImageColumns.BUCKET_DISPLAY_NAME); 3708702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // If the data is being modified update the bucket values 3709702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String data = values.getAsString(MediaColumns.DATA); 3710702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (data != null) { 3711702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project computeBucketValues(data, values); 3712702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3713b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen computeTakenTime(values); 371410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumUpdates++; 3715702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count = db.update(sGetTableAndWhereParam.table, values, 3716702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sGetTableAndWhereParam.where, whereArgs); 371701a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen // if this is a request from MediaScanner, DATA should contains file path 371801a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen // we only process update request from media scanner, otherwise the requests 371901a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen // could be duplicate. 372001a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen if (count > 0 && values.getAsString(MediaStore.MediaColumns.DATA) != null) { 372110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumQueries++; 372201a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen Cursor c = db.query(sGetTableAndWhereParam.table, 372301a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen READY_FLAG_PROJECTION, sGetTableAndWhereParam.where, 372401a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen whereArgs, null, null, null); 3725b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (c != null) { 3726216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen try { 3727216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen while (c.moveToNext()) { 3728216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen long magic = c.getLong(2); 3729216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen if (magic == 0) { 3730216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen requestMediaThumbnail(c.getString(1), uri, 3731216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen MediaThumbRequest.PRIORITY_NORMAL, 0); 3732216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen } 3733b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 3734216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen } finally { 3735216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen c.close(); 3736b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 3737b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 3738b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 3739702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3740702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3741f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen 3742f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen case AUDIO_PLAYLISTS_ID_MEMBERS_ID: 3743f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen String moveit = uri.getQueryParameter("move"); 3744f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen if (moveit != null) { 3745f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen String key = MediaStore.Audio.Playlists.Members.PLAY_ORDER; 3746f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen if (initialValues.containsKey(key)) { 3747f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen int newpos = initialValues.getAsInteger(key); 3748f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen List <String> segments = uri.getPathSegments(); 3749f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen long playlist = Long.valueOf(segments.get(3)); 3750f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen int oldpos = Integer.valueOf(segments.get(5)); 375110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen return movePlaylistEntry(helper, db, playlist, oldpos, newpos); 3752f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } 3753f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen throw new IllegalArgumentException("Need to specify " + key + 3754f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " when using 'move' parameter"); 3755f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } 3756f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen // fall through 3757702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project default: 375810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumUpdates++; 3759702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count = db.update(sGetTableAndWhereParam.table, initialValues, 3760702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sGetTableAndWhereParam.where, whereArgs); 3761702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3762702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3763702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3764cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen // in a transaction, the code that began the transaction should be taking 3765cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen // care of notifications once it ends the transaction successfully 3766cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen if (count > 0 && !db.inTransaction()) { 3767702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 3768702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3769702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return count; 3770702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3771702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 377210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen private int movePlaylistEntry(DatabaseHelper helper, SQLiteDatabase db, 377310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen long playlist, int from, int to) { 3774f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen if (from == to) { 3775f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen return 0; 3776f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } 3777f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen db.beginTransaction(); 3778f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen try { 3779f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen int numlines = 0; 378010af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumUpdates += 3; 3781f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen db.execSQL("UPDATE audio_playlists_map SET play_order=-1" + 3782f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " WHERE play_order=" + from + 3783f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " AND playlist_id=" + playlist); 3784f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen // We could just run both of the next two statements, but only one of 3785f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen // of them will actually do anything, so might as well skip the compile 3786f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen // and execute steps. 3787f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen if (from < to) { 3788f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen db.execSQL("UPDATE audio_playlists_map SET play_order=play_order-1" + 3789f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " WHERE play_order<=" + to + " AND play_order>" + from + 3790f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " AND playlist_id=" + playlist); 3791f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen numlines = to - from + 1; 3792f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } else { 3793f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen db.execSQL("UPDATE audio_playlists_map SET play_order=play_order+1" + 3794f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " WHERE play_order>=" + to + " AND play_order<" + from + 3795f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " AND playlist_id=" + playlist); 3796f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen numlines = from - to + 1; 3797f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } 3798f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen db.execSQL("UPDATE audio_playlists_map SET play_order=" + to + 3799f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " WHERE play_order=-1 AND playlist_id=" + playlist); 3800f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen db.setTransactionSuccessful(); 3801f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen Uri uri = MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI 3802f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen .buildUpon().appendEncodedPath(String.valueOf(playlist)).build(); 3803f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen getContext().getContentResolver().notifyChange(uri, null); 3804f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen return numlines; 3805f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } finally { 3806f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen db.endTransaction(); 3807f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } 3808f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } 3809f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen 3810702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final String[] openFileColumns = new String[] { 3811702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.MediaColumns.DATA, 3812702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project }; 3813702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3814702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 3815702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public ParcelFileDescriptor openFile(Uri uri, String mode) 3816702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throws FileNotFoundException { 381771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen 3818702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ParcelFileDescriptor pfd = null; 381971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen 382071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (URI_MATCHER.match(uri) == AUDIO_ALBUMART_FILE_ID) { 382171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // get album art for the specified media file 382271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen DatabaseHelper database = getDatabaseForUri(uri); 382371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (database == null) { 382471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen throw new IllegalStateException("Couldn't open database for " + uri); 382571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 382671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen SQLiteDatabase db = database.getReadableDatabase(); 38275fde670987a55d69442566dcbdb7830d5f1587c6Chih-Chung Chang if (db == null) { 38285fde670987a55d69442566dcbdb7830d5f1587c6Chih-Chung Chang throw new IllegalStateException("Couldn't open database for " + uri); 38295fde670987a55d69442566dcbdb7830d5f1587c6Chih-Chung Chang } 383071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 383171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen int songid = Integer.parseInt(uri.getPathSegments().get(3)); 383271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen qb.setTables("audio_meta"); 383371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen qb.appendWhere("_id=" + songid); 383471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen Cursor c = qb.query(db, 383571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen new String [] { 383671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen MediaStore.Audio.Media.DATA, 383771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen MediaStore.Audio.Media.ALBUM_ID }, 383871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen null, null, null, null, null); 383971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (c.moveToFirst()) { 384071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen String audiopath = c.getString(0); 384171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen int albumid = c.getInt(1); 384271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // Try to get existing album art for this album first, which 384371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // could possibly have been obtained from a different file. 384471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // If that fails, try to get it from this specific file. 384571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen Uri newUri = ContentUris.withAppendedId(ALBUMART_URI, albumid); 384671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen try { 38473fa7593ce394cdaad4a3db622d415fd8497f4a9dMarco Nelissen pfd = openFileHelper(newUri, mode); 384871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } catch (FileNotFoundException ex) { 384971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // That didn't work, now try to get it from the specific file 385071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen pfd = getThumb(db, audiopath, albumid, null); 385171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 385271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 385371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen c.close(); 385471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen return pfd; 385571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 385671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen 3857702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 3858702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project pfd = openFileHelper(uri, mode); 3859702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } catch (FileNotFoundException ex) { 386071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (mode.contains("w")) { 386171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // if the file couldn't be created, we shouldn't extract album art 386271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen throw ex; 386371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 386471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen 3865702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (URI_MATCHER.match(uri) == AUDIO_ALBUMART_ID) { 3866702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Tried to open an album art file which does not exist. Regenerate. 3867702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DatabaseHelper database = getDatabaseForUri(uri); 3868702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (database == null) { 3869702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw ex; 3870702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3871702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteDatabase db = database.getReadableDatabase(); 38725fde670987a55d69442566dcbdb7830d5f1587c6Chih-Chung Chang if (db == null) { 38735fde670987a55d69442566dcbdb7830d5f1587c6Chih-Chung Chang throw new IllegalStateException("Couldn't open database for " + uri); 38745fde670987a55d69442566dcbdb7830d5f1587c6Chih-Chung Chang } 3875702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 3876702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int albumid = Integer.parseInt(uri.getPathSegments().get(3)); 387771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen qb.setTables("audio_meta"); 3878702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("album_id=" + albumid); 3879702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Cursor c = qb.query(db, 3880702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project new String [] { 3881702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.Audio.Media.DATA }, 3882a4d7f8a140c9a66bfcb28c5197521db6d62e13beMarco Nelissen null, null, null, null, MediaStore.Audio.Media.TRACK); 388371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (c.moveToFirst()) { 3884702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String audiopath = c.getString(0); 388571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen pfd = getThumb(db, audiopath, albumid, uri); 3886702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3887702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project c.close(); 3888702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 388971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (pfd == null) { 389071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen throw ex; 389171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 3892702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3893702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return pfd; 3894702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3895702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3896702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private class ThumbData { 389710af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen DatabaseHelper helper; 3898702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteDatabase db; 3899702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String path; 3900702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long album_id; 3901702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Uri albumart_uri; 3902702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3903702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 390410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen private void makeThumbAsync(DatabaseHelper helper, SQLiteDatabase db, 390510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen String path, long album_id) { 39068a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber synchronized (mPendingThumbs) { 39078a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (mPendingThumbs.contains(path)) { 39088a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // There's already a request to make an album art thumbnail 39098a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // for this audio file in the queue. 39108a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber return; 39118a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 39128a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 39138a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber mPendingThumbs.add(path); 39148a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 39158a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 3916702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ThumbData d = new ThumbData(); 391710af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen d.helper = helper; 3918702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project d.db = db; 3919702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project d.path = path; 3920702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project d.album_id = album_id; 3921a9c4e330dacb37cfffa9c00f7da83cafde4accefMarco Nelissen d.albumart_uri = ContentUris.withAppendedId(mAlbumArtBaseUri, album_id); 39228a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 39238a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // Instead of processing thumbnail requests in the order they were 39248a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // received we instead process them stack-based, i.e. LIFO. 39258a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // The idea behind this is that the most recently requested thumbnails 39268a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // are most likely the ones still in the user's view, whereas those 39278a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // requested earlier may have already scrolled off. 39288a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber synchronized (mThumbRequestStack) { 39298a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber mThumbRequestStack.push(d); 39308a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 39318a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 39328a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // Trigger the handler. 3933b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen Message msg = mThumbHandler.obtainMessage(ALBUM_THUMB); 3934702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project msg.sendToTarget(); 3935702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3936702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 39378a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // Extract compressed image data from the audio file itself or, if that fails, 39388a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // look for a file "AlbumArt.jpg" in the containing directory. 39398a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber private static byte[] getCompressedAlbumArt(Context context, String path) { 39408a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber byte[] compressed = null; 3941702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3942702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 3943702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File f = new File(path); 3944702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ParcelFileDescriptor pfd = ParcelFileDescriptor.open(f, 3945702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ParcelFileDescriptor.MODE_READ_ONLY); 3946702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 39478a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber MediaScanner scanner = new MediaScanner(context); 39488a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber compressed = scanner.extractAlbumArt(pfd.getFileDescriptor()); 3949702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project pfd.close(); 3950702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3951d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // If no embedded art exists, look for a suitable image file in the 39523f9c37ea95a3bdf5f84dc79eb199256c4deda29aMarco Nelissen // same directory as the media file, except if that directory is 39533f9c37ea95a3bdf5f84dc79eb199256c4deda29aMarco Nelissen // is the root directory of the sd card or the download directory. 3954d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // We look for, in order of preference: 3955d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // 0 AlbumArt.jpg 3956d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // 1 AlbumArt*Large.jpg 3957d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // 2 Any other jpg image with 'albumart' anywhere in the name 3958d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // 3 Any other jpg image 3959d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // 4 any other png image 39608a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (compressed == null && path != null) { 3961702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int lastSlash = path.lastIndexOf('/'); 3962702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (lastSlash > 0) { 3963d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen 39643f9c37ea95a3bdf5f84dc79eb199256c4deda29aMarco Nelissen String artPath = path.substring(0, lastSlash); 39659be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood String sdroot = mExternalStoragePaths[0]; 39660fe3097230b324e65a874bd7c8c0f430d2fb8cbeMarco Nelissen String dwndir = Environment.getExternalStoragePublicDirectory( 39672f07f572bc574b685b491ee07a6209c7f2dcb13fMarco Nelissen Environment.DIRECTORY_DOWNLOADS).getAbsolutePath(); 3968d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen 3969d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen String bestmatch = null; 3970d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen synchronized (sFolderArtMap) { 3971d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen if (sFolderArtMap.containsKey(artPath)) { 3972d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = sFolderArtMap.get(artPath); 3973ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen } else if (!artPath.equalsIgnoreCase(sdroot) && 3974ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen !artPath.equalsIgnoreCase(dwndir)) { 3975d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen File dir = new File(artPath); 3976d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen String [] entrynames = dir.list(); 3977d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen if (entrynames == null) { 3978d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen return null; 3979d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } 3980d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = null; 3981d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen int matchlevel = 1000; 3982d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen for (int i = entrynames.length - 1; i >=0; i--) { 3983d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen String entry = entrynames[i].toLowerCase(); 3984d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen if (entry.equals("albumart.jpg")) { 3985d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = entrynames[i]; 3986d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen break; 3987d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } else if (entry.startsWith("albumart") 3988d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen && entry.endsWith("large.jpg") 3989d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen && matchlevel > 1) { 3990d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = entrynames[i]; 3991d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen matchlevel = 1; 3992d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } else if (entry.contains("albumart") 3993d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen && entry.endsWith(".jpg") 3994d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen && matchlevel > 2) { 3995d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = entrynames[i]; 3996d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen matchlevel = 2; 3997d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } else if (entry.endsWith(".jpg") && matchlevel > 3) { 3998d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = entrynames[i]; 3999d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen matchlevel = 3; 4000d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } else if (entry.endsWith(".png") && matchlevel > 4) { 4001d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = entrynames[i]; 4002d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen matchlevel = 4; 4003d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } 4004d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } 4005d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // note that this may insert null if no album art was found 4006d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen sFolderArtMap.put(artPath, bestmatch); 4007d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } 4008d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } 4009d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen 4010d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen if (bestmatch != null) { 40113f9c37ea95a3bdf5f84dc79eb199256c4deda29aMarco Nelissen File file = new File(artPath, bestmatch); 4012d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen if (file.exists()) { 4013d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen compressed = new byte[(int)file.length()]; 4014d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen FileInputStream stream = null; 4015d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen try { 4016d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen stream = new FileInputStream(file); 4017d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen stream.read(compressed); 4018d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } catch (IOException ex) { 4019d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen compressed = null; 4020d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } finally { 4021d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen if (stream != null) { 4022d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen stream.close(); 4023d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } 4024702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4025702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4026702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4027702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4028702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 40298a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } catch (IOException e) { 40308a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 4031702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 40328a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber return compressed; 40338a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 4034702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 40358a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // Return a URI to write the album art to and update the database as necessary. 403610af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen Uri getAlbumArtOutputUri(DatabaseHelper helper, SQLiteDatabase db, long album_id, Uri albumart_uri) { 40378a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber Uri out = null; 40388a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // TODO: this could be done more efficiently with a call to db.replace(), which 40398a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // replaces or inserts as needed, making it unnecessary to query() first. 40408a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (albumart_uri != null) { 4041801ba04ac37ee06dccb8bf4081b29a162795e3a6Mike Lockwood Cursor c = query(albumart_uri, new String [] { MediaStore.MediaColumns.DATA }, 40428a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber null, null, null); 4043d8c100241c1c8983deeae6329111e2bce997294dJoakim Johansson try { 4044d8c100241c1c8983deeae6329111e2bce997294dJoakim Johansson if (c != null && c.moveToFirst()) { 4045d8c100241c1c8983deeae6329111e2bce997294dJoakim Johansson String albumart_path = c.getString(0); 4046d8c100241c1c8983deeae6329111e2bce997294dJoakim Johansson if (ensureFileExists(albumart_path)) { 4047d8c100241c1c8983deeae6329111e2bce997294dJoakim Johansson out = albumart_uri; 4048d8c100241c1c8983deeae6329111e2bce997294dJoakim Johansson } 4049d8c100241c1c8983deeae6329111e2bce997294dJoakim Johansson } else { 4050d8c100241c1c8983deeae6329111e2bce997294dJoakim Johansson albumart_uri = null; 4051d8c100241c1c8983deeae6329111e2bce997294dJoakim Johansson } 4052d8c100241c1c8983deeae6329111e2bce997294dJoakim Johansson } finally { 4053d8c100241c1c8983deeae6329111e2bce997294dJoakim Johansson if (c != null) { 4054d8c100241c1c8983deeae6329111e2bce997294dJoakim Johansson c.close(); 4055702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4056702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 405771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 405871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (albumart_uri == null){ 40598a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber ContentValues initialValues = new ContentValues(); 40608a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber initialValues.put("album_id", album_id); 40618a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber try { 40628a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber ContentValues values = ensureFile(false, initialValues, "", ALBUM_THUMB_FOLDER); 406310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumInserts++; 4064801ba04ac37ee06dccb8bf4081b29a162795e3a6Mike Lockwood long rowId = db.insert("album_art", MediaStore.MediaColumns.DATA, values); 40658a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (rowId > 0) { 40668a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber out = ContentUris.withAppendedId(ALBUMART_URI, rowId); 4067702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 40688a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } catch (IllegalStateException ex) { 40698a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber Log.e(TAG, "error creating album thumb file"); 40708a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 40718a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 40728a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber return out; 40738a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 40748a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 40758a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // Write out the album art to the output URI, recompresses the given Bitmap 40768a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // if necessary, otherwise writes the compressed data. 40778a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber private void writeAlbumArt( 40788a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber boolean need_to_recompress, Uri out, byte[] compressed, Bitmap bm) { 40798a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber boolean success = false; 40808a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber try { 40818a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber OutputStream outstream = getContext().getContentResolver().openOutputStream(out); 40828a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 40838a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (!need_to_recompress) { 40848a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // No need to recompress here, just write out the original 40858a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // compressed data here. 40868a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber outstream.write(compressed); 40878a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber success = true; 40888a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } else { 408970676508bd3a081edd909875e141f2c48d79c1acDaniel Lehmann success = bm.compress(Bitmap.CompressFormat.JPEG, 85, outstream); 4090702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 40918a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 40928a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber outstream.close(); 40938a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } catch (FileNotFoundException ex) { 40948a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber Log.e(TAG, "error creating file", ex); 4095702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } catch (IOException ex) { 40968a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber Log.e(TAG, "error creating file", ex); 40978a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 40988a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (!success) { 40998a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // the thumbnail was not written successfully, delete the entry that refers to it 41008a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber getContext().getContentResolver().delete(out, null, null); 4101702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 41028a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 41038a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 410471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen private ParcelFileDescriptor getThumb(SQLiteDatabase db, String path, long album_id, 410571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen Uri albumart_uri) { 410671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen ThumbData d = new ThumbData(); 410771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen d.db = db; 410871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen d.path = path; 410971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen d.album_id = album_id; 411071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen d.albumart_uri = albumart_uri; 411171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen return makeThumbInternal(d); 411271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 411371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen 411471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen private ParcelFileDescriptor makeThumbInternal(ThumbData d) { 41158a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber byte[] compressed = getCompressedAlbumArt(getContext(), d.path); 4116702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 41178a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (compressed == null) { 411871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen return null; 41198a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 41208a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 41218a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber Bitmap bm = null; 41228a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber boolean need_to_recompress = true; 41238a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 41248a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber try { 41258a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // get the size of the bitmap 41268a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber BitmapFactory.Options opts = new BitmapFactory.Options(); 41278a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.inJustDecodeBounds = true; 41288a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.inSampleSize = 1; 41298a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber BitmapFactory.decodeByteArray(compressed, 0, compressed.length, opts); 41308a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 41318a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // request a reasonably sized output image 413270676508bd3a081edd909875e141f2c48d79c1acDaniel Lehmann final Resources r = getContext().getResources(); 413370676508bd3a081edd909875e141f2c48d79c1acDaniel Lehmann final int maximumThumbSize = r.getDimensionPixelSize(R.dimen.maximum_thumb_size); 413470676508bd3a081edd909875e141f2c48d79c1acDaniel Lehmann while (opts.outHeight > maximumThumbSize || opts.outWidth > maximumThumbSize) { 41358a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.outHeight /= 2; 41368a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.outWidth /= 2; 41378a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.inSampleSize *= 2; 41388a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 41398a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 41408a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (opts.inSampleSize == 1) { 41418a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // The original album art was of proper size, we won't have to 41428a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // recompress the bitmap later. 41438a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber need_to_recompress = false; 41448a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } else { 41458a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // get the image for real now 41468a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.inJustDecodeBounds = false; 41478a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.inPreferredConfig = Bitmap.Config.RGB_565; 41488a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber bm = BitmapFactory.decodeByteArray(compressed, 0, compressed.length, opts); 41498a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 41508a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (bm != null && bm.getConfig() == null) { 4151a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen Bitmap nbm = bm.copy(Bitmap.Config.RGB_565, false); 4152a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen if (nbm != null && nbm != bm) { 4153a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen bm.recycle(); 4154a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen bm = nbm; 4155a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen } 41568a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 41578a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 41588a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } catch (Exception e) { 41598a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 41608a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 41618a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (need_to_recompress && bm == null) { 416271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen return null; 41638a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 41648a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 416571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (d.albumart_uri == null) { 416671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // this one doesn't need to be saved (probably a song with an unknown album), 416771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // so stick it in a memory file and return that 416871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen try { 416924001394f571b1f0378840cbf299288e4df10508Bjorn Bringert return ParcelFileDescriptor.fromData(compressed, "albumthumb"); 417071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } catch (IOException e) { 417171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 417271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } else { 4173a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen // This one needs to actually be saved on the sd card. 4174a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen // This is wrapped in a transaction because there are various things 4175a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen // that could go wrong while generating the thumbnail, and we only want 4176a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen // to update the database when all steps succeeded. 4177a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen d.db.beginTransaction(); 4178a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen try { 417910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen Uri out = getAlbumArtOutputUri(d.helper, d.db, d.album_id, d.albumart_uri); 4180a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen 4181a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen if (out != null) { 4182a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen writeAlbumArt(need_to_recompress, out, compressed, bm); 4183a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen getContext().getContentResolver().notifyChange(MEDIA_URI, null); 4184a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen ParcelFileDescriptor pfd = openFileHelper(out, "r"); 4185a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen d.db.setTransactionSuccessful(); 4186a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen return pfd; 4187a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen } 4188a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen } catch (FileNotFoundException ex) { 4189a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen // do nothing, just return null below 4190a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen } catch (UnsupportedOperationException ex) { 4191a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen // do nothing, just return null below 4192a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen } finally { 4193a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen d.db.endTransaction(); 4194a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen if (bm != null) { 4195a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen bm.recycle(); 419671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 419771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 41988a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 419971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen return null; 4200702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4201702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4202702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 4203702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Look up the artist or album entry for the given name, creating that entry 4204702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * if it does not already exists. 4205702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param db The database 4206702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param table The table to store the key/name pair in. 4207702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param keyField The name of the key-column 4208702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param nameField The name of the name-column 4209702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param rawName The name that the calling app was trying to insert into the database 421059948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen * @param cacheName The string that will be inserted in to the cache 421159948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen * @param path The full path to the file being inserted in to the audio table 421259948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen * @param albumHash A hash to distinguish between different albums of the same name 4213a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen * @param artist The name of the artist, if known 4214702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param cache The cache to add this entry to 4215702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param srcuri The Uri that prompted the call to this method, used for determining whether this is 4216702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * the internal or external database 4217702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @return The row ID for this artist/album, or -1 if the provided name was invalid 4218702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 421910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen private long getKeyIdForName(DatabaseHelper helper, SQLiteDatabase db, 422010af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen String table, String keyField, String nameField, 422159948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen String rawName, String cacheName, String path, int albumHash, 4222a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen String artist, HashMap<String, Long> cache, Uri srcuri) { 4223702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long rowId; 4224702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4225702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rawName == null || rawName.length() == 0) { 422651cba5e1acf1c56be3dc6c7c46a73a5a0409b452Marco Nelissen rawName = MediaStore.UNKNOWN_STRING; 4227702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4228702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String k = MediaStore.Audio.keyFor(rawName); 4229702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4230702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (k == null) { 423151cba5e1acf1c56be3dc6c7c46a73a5a0409b452Marco Nelissen // shouldn't happen, since we only get null keys for null inputs 423251cba5e1acf1c56be3dc6c7c46a73a5a0409b452Marco Nelissen Log.e(TAG, "null key", new Exception()); 4233702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return -1; 4234702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4235702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 423659948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen boolean isAlbum = table.equals("albums"); 4237e31cfb1a2c21e7ac7a646d40afbb48f49fab6907Marco Nelissen boolean isUnknown = MediaStore.UNKNOWN_STRING.equals(rawName); 423859948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen 42392658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen // To distinguish same-named albums, we append a hash. The hash is based 42402658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen // on the "album artist" tag if present, otherwise on the "compilation" tag 42412658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen // if present, otherwise on the path. 424259948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // Ideally we would also take things like CDDB ID in to account, so 424359948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // we can group files from the same album that aren't in the same 424459948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // folder, but this is a quick and easy start that works immediately 424559948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // without requiring support from the mp3, mp4 and Ogg meta data 424659948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // readers, as long as the albums are in different folders. 4247a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen if (isAlbum) { 424859948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen k = k + albumHash; 4249a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen if (isUnknown) { 4250a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen k = k + artist; 4251a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen } 425259948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen } 425359948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen 4254702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String [] selargs = { k }; 425510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumQueries++; 4256702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Cursor c = db.query(table, null, keyField + "=?", selargs, null, null, null); 4257702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4258702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 4259702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (c.getCount()) { 4260702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case 0: { 4261702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // insert new entry into table 4262702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues otherValues = new ContentValues(); 4263702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project otherValues.put(keyField, k); 4264702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project otherValues.put(nameField, rawName); 426510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumInserts++; 4266702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert(table, "duration", otherValues); 426759948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen if (path != null && isAlbum && ! isUnknown) { 4268702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // We just inserted a new album. Now create an album art thumbnail for it. 426910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen makeThumbAsync(helper, db, path, rowId); 4270702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4271702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 4272702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String volume = srcuri.toString().substring(16, 24); // extract internal/external 4273702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Uri uri = Uri.parse("content://media/" + volume + "/audio/" + table + "/" + rowId); 4274702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 4275702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4276702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4277702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 4278702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case 1: { 4279702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Use the existing entry 4280702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project c.moveToFirst(); 4281702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = c.getLong(0); 4282702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4283702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Determine whether the current rawName is better than what's 4284702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // currently stored in the table, and update the table if it is. 4285702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String currentFancyName = c.getString(2); 4286702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String bestName = makeBestName(rawName, currentFancyName); 4287702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!bestName.equals(currentFancyName)) { 4288702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // update the table with the new name 4289702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues newValues = new ContentValues(); 4290702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newValues.put(nameField, bestName); 429110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumUpdates++; 4292702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.update(table, newValues, "rowid="+Integer.toString((int)rowId), null); 4293702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String volume = srcuri.toString().substring(16, 24); // extract internal/external 4294702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Uri uri = Uri.parse("content://media/" + volume + "/audio/" + table + "/" + rowId); 4295702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 4296702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4297702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4298702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 4299702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project default: 4300702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // corrupt database 4301702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Log.e(TAG, "Multiple entries in table " + table + " for key " + k); 4302702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = -1; 4303702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 4304702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4305702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 4306702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (c != null) c.close(); 4307702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4308702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 430959948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen if (cache != null && ! isUnknown) { 431059948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen cache.put(cacheName, rowId); 4311702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4312702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return rowId; 4313702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4314702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4315702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 4316702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Returns the best string to use for display, given two names. 4317702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Note that this function does not necessarily return either one 4318702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * of the provided names; it may decide to return a better alternative 4319702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * (for example, specifying the inputs "Police" and "Police, The" will 4320702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * return "The Police") 4321702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 4322702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * The basic assumptions are: 4323702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * - longer is better ("The police" is better than "Police") 4324702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * - prefix is better ("The Police" is better than "Police, The") 4325702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * - accents are better ("Motörhead" is better than "Motorhead") 4326702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 4327702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param one The first of the two names to consider 4328702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param two The last of the two names to consider 4329702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @return The actual name to use 4330702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 4331702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String makeBestName(String one, String two) { 4332702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String name; 4333702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4334702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Longer names are usually better. 4335702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (one.length() > two.length()) { 4336702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project name = one; 4337702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 4338702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Names with accents are usually better, and conveniently sort later 4339702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (one.toLowerCase().compareTo(two.toLowerCase()) > 0) { 4340702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project name = one; 4341702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 4342702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project name = two; 4343702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4344702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4345702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4346702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Prefixes are better than postfixes. 4347702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (name.endsWith(", the") || name.endsWith(",the") || 4348702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project name.endsWith(", an") || name.endsWith(",an") || 4349702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project name.endsWith(", a") || name.endsWith(",a")) { 4350702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String fix = name.substring(1 + name.lastIndexOf(',')); 4351702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project name = fix.trim() + " " + name.substring(0, name.lastIndexOf(',')); 4352702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4353702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4354702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // TODO: word-capitalize the resulting name 4355702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return name; 4356702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4357702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4358702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4359702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 4360702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Looks up the database based on the given URI. 4361702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 4362702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param uri The requested URI 4363702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @returns the database for the given URI 4364702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 4365702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private DatabaseHelper getDatabaseForUri(Uri uri) { 4366702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized (mDatabases) { 4367702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (uri.getPathSegments().size() > 1) { 4368702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return mDatabases.get(uri.getPathSegments().get(0)); 4369702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4370702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4371702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return null; 4372702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4373702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4374fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn static boolean isMediaDatabaseName(String name) { 4375fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn if (INTERNAL_DATABASE_NAME.equals(name)) { 4376fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn return true; 4377fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn } 4378fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn if (EXTERNAL_DATABASE_NAME.equals(name)) { 4379fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn return true; 4380fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn } 4381fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn if (name.startsWith("external-")) { 4382fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn return true; 4383fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn } 4384fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn return false; 4385fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn } 4386fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn 4387fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn static boolean isInternalMediaDatabaseName(String name) { 4388fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn if (INTERNAL_DATABASE_NAME.equals(name)) { 4389fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn return true; 4390fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn } 4391fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn return false; 4392fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn } 4393fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn 4394702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 4395702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Attach the database for a volume (internal or external). 4396702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Does nothing if the volume is already attached, otherwise 4397702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * checks the volume ID and sets up the corresponding database. 4398702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 4399702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param volume to attach, either {@link #INTERNAL_VOLUME} or {@link #EXTERNAL_VOLUME}. 4400702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @return the content URI of the attached volume. 4401702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 4402702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private Uri attachVolume(String volume) { 440375392afde5217038b0c98077758bb9329c2431b2Jeff Brown if (Binder.getCallingPid() != Process.myPid()) { 4404702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new SecurityException( 4405702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Opening and closing databases not allowed."); 4406702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4407702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4408702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized (mDatabases) { 4409702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (mDatabases.get(volume) != null) { // Already attached 4410702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Uri.parse("content://media/" + volume); 4411702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4412702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4413993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood Context context = getContext(); 441410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen DatabaseHelper helper; 4415702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (INTERNAL_VOLUME.equals(volume)) { 441610af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper = new DatabaseHelper(context, INTERNAL_DATABASE_NAME, true, 4417fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn false, mObjectRemovedCallback); 4418702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else if (EXTERNAL_VOLUME.equals(volume)) { 4419993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood if (Environment.isExternalStorageRemovable()) { 44209be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood String path = mExternalStoragePaths[0]; 4421993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood int volumeID = FileUtils.getFatVolumeId(path); 4422993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood if (LOCAL_LOGV) Log.v(TAG, path + " volume ID: " + volumeID); 4423993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood 4424993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood // generate database name based on volume ID 4425993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood String dbName = "external-" + Integer.toHexString(volumeID) + ".db"; 442610af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper = new DatabaseHelper(context, dbName, false, 4427fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn false, mObjectRemovedCallback); 4428993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood mVolumeId = volumeID; 4429993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood } else { 4430993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood // external database name should be EXTERNAL_DATABASE_NAME 4431993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood // however earlier releases used the external-XXXXXXXX.db naming 4432993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood // for devices without removable storage, and in that case we need to convert 4433993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood // to this new convention 4434993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood File dbFile = context.getDatabasePath(EXTERNAL_DATABASE_NAME); 4435993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood if (!dbFile.exists()) { 4436993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood // find the most recent external database and rename it to 4437993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood // EXTERNAL_DATABASE_NAME, and delete any other older 4438993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood // external database files 4439993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood File recentDbFile = null; 4440993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood for (String database : context.databaseList()) { 4441993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood if (database.startsWith("external-")) { 4442993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood File file = context.getDatabasePath(database); 4443993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood if (recentDbFile == null) { 4444993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood recentDbFile = file; 4445993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood } else if (file.lastModified() > recentDbFile.lastModified()) { 4446993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood recentDbFile.delete(); 4447993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood recentDbFile = file; 4448993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood } else { 4449993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood file.delete(); 4450993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood } 4451993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood } 4452993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood } 4453993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood if (recentDbFile != null) { 4454993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood if (recentDbFile.renameTo(dbFile)) { 4455993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood Log.d(TAG, "renamed database " + recentDbFile.getName() + 4456993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood " to " + EXTERNAL_DATABASE_NAME); 4457993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood } else { 4458993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood Log.e(TAG, "Failed to rename database " + recentDbFile.getName() + 4459993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood " to " + EXTERNAL_DATABASE_NAME); 4460993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood // This shouldn't happen, but if it does, continue using 4461993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood // the file under its old name 4462993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood dbFile = recentDbFile; 4463993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood } 4464993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood } 4465993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood // else DatabaseHelper will create one named EXTERNAL_DATABASE_NAME 4466993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood } 446710af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper = new DatabaseHelper(context, dbFile.getName(), false, 4468fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn false, mObjectRemovedCallback); 4469993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood } 4470702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 4471702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalArgumentException("There is no volume named " + volume); 4472702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4473702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 447410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen mDatabases.put(volume, helper); 4475702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 447610af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen if (!helper.mInternal) { 4477ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood // create default directories (only happens on first boot) 447810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen createDefaultFolders(helper, helper.getWritableDatabase()); 4479ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood 4480702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // clean up stray album art files: delete every file not in the database 44819be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood File[] files = new File(mExternalStoragePaths[0], ALBUM_THUMB_FOLDER).listFiles(); 4482702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project HashSet<String> fileSet = new HashSet(); 4483702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project for (int i = 0; files != null && i < files.length; i++) { 4484702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project fileSet.add(files[i].getPath()); 4485702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4486702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4487702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Cursor cursor = query(MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI, 4488702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project new String[] { MediaStore.Audio.Albums.ALBUM_ART }, null, null, null); 4489702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 4490702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project while (cursor != null && cursor.moveToNext()) { 4491702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project fileSet.remove(cursor.getString(0)); 4492702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4493702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 4494702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (cursor != null) cursor.close(); 4495702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4496702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4497702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Iterator<String> iterator = fileSet.iterator(); 4498702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project while (iterator.hasNext()) { 4499702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String filename = iterator.next(); 4500702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (LOCAL_LOGV) Log.v(TAG, "deleting obsolete album art " + filename); 4501702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project new File(filename).delete(); 4502702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4503702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4504702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4505702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4506702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (LOCAL_LOGV) Log.v(TAG, "Attached volume: " + volume); 4507702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Uri.parse("content://media/" + volume); 4508702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4509702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4510702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 4511702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Detach the database for a volume (must be external). 4512702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Does nothing if the volume is already detached, otherwise 4513702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * closes the database and sends a notification to listeners. 4514702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 4515702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param uri The content URI of the volume, as returned by {@link #attachVolume} 4516702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 4517702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private void detachVolume(Uri uri) { 451875392afde5217038b0c98077758bb9329c2431b2Jeff Brown if (Binder.getCallingPid() != Process.myPid()) { 4519702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new SecurityException( 4520702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Opening and closing databases not allowed."); 4521702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4522702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4523702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String volume = uri.getPathSegments().get(0); 4524702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (INTERNAL_VOLUME.equals(volume)) { 4525702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException( 4526702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Deleting the internal volume is not allowed"); 4527702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else if (!EXTERNAL_VOLUME.equals(volume)) { 4528702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalArgumentException( 4529702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "There is no volume named " + volume); 4530702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4531702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4532702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized (mDatabases) { 4533702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DatabaseHelper database = mDatabases.get(volume); 4534702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (database == null) return; 4535702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4536702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 4537702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // touch the database file to show it is most recently used 4538702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File file = new File(database.getReadableDatabase().getPath()); 4539702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project file.setLastModified(System.currentTimeMillis()); 4540e9ee0248d62f3badef8a554f35f78e9116ef8a5cMike Lockwood } catch (Exception e) { 4541702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Log.e(TAG, "Can't touch database file", e); 4542702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4543702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4544702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mDatabases.remove(volume); 4545702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project database.close(); 4546702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4547702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4548702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 4549702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (LOCAL_LOGV) Log.v(TAG, "Detached volume: " + volume); 4550702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4551702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4552702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static String TAG = "MediaProvider"; 4553ae62a1d602e7ed2e0e30e271bddbb27aa71469f6Christian Mehlmauer private static final boolean LOCAL_LOGV = false; 4554971a2ef5165e2072c76bf25049fdda94187019c2Dianne Hackborn 4555bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang static final int DATABASE_VERSION = 408; 4556702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final String INTERNAL_DATABASE_NAME = "internal.db"; 4557993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood private static final String EXTERNAL_DATABASE_NAME = "external.db"; 4558702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4559702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // maximum number of cached external databases to keep 4560702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int MAX_EXTERNAL_DATABASES = 3; 4561702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4562702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Delete databases that have not been used in two months 4563702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // 60 days in milliseconds (1000 * 60 * 60 * 24 * 60) 4564702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final long OBSOLETE_DATABASE_DB = 5184000000L; 4565702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4566702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private HashMap<String, DatabaseHelper> mDatabases; 4567702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4568702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private Handler mThumbHandler; 4569702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4570702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // name of the volume currently being scanned by the media scanner (or null) 4571702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private String mMediaScannerVolume; 4572702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 45730027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen // current FAT volume ID 4574993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood private int mVolumeId = -1; 45750027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen 4576702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project static final String INTERNAL_VOLUME = "internal"; 4577702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project static final String EXTERNAL_VOLUME = "external"; 4578268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen static final String ALBUM_THUMB_FOLDER = "Android/data/com.android.providers.media/albumthumbs"; 4579702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4580702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // path for writing contents of in memory temp database 4581702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private String mTempDatabasePath; 4582702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 45831717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood // WARNING: the values of IMAGES_MEDIA, AUDIO_MEDIA, and VIDEO_MEDIA and AUDIO_PLAYLISTS 458416dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood // are stored in the "files" table, so do not renumber them unless you also add 45851717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood // a corresponding database upgrade step for it. 4586702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int IMAGES_MEDIA = 1; 4587702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int IMAGES_MEDIA_ID = 2; 4588702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int IMAGES_THUMBNAILS = 3; 4589702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int IMAGES_THUMBNAILS_ID = 4; 4590702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4591702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_MEDIA = 100; 4592702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_MEDIA_ID = 101; 4593702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_MEDIA_ID_GENRES = 102; 4594702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_MEDIA_ID_GENRES_ID = 103; 4595702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_MEDIA_ID_PLAYLISTS = 104; 4596702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_MEDIA_ID_PLAYLISTS_ID = 105; 4597702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_GENRES = 106; 4598702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_GENRES_ID = 107; 4599702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_GENRES_ID_MEMBERS = 108; 4600bfbc30ff3b9e3a96b08c525d0971d8d8543ab000Marco Nelissen private static final int AUDIO_GENRES_ALL_MEMBERS = 109; 4601702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_PLAYLISTS = 110; 4602702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_PLAYLISTS_ID = 111; 4603702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_PLAYLISTS_ID_MEMBERS = 112; 4604702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_PLAYLISTS_ID_MEMBERS_ID = 113; 4605702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ARTISTS = 114; 4606702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ARTISTS_ID = 115; 4607702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ALBUMS = 116; 4608702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ALBUMS_ID = 117; 4609702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ARTISTS_ID_ALBUMS = 118; 4610702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ALBUMART = 119; 4611702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ALBUMART_ID = 120; 461271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen private static final int AUDIO_ALBUMART_FILE_ID = 121; 4613702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4614702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int VIDEO_MEDIA = 200; 4615702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int VIDEO_MEDIA_ID = 201; 4616b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private static final int VIDEO_THUMBNAILS = 202; 4617b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private static final int VIDEO_THUMBNAILS_ID = 203; 4618702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4619702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int VOLUMES = 300; 4620702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int VOLUMES_ID = 301; 4621702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4622a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen private static final int AUDIO_SEARCH_LEGACY = 400; 4623a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen private static final int AUDIO_SEARCH_BASIC = 401; 4624a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen private static final int AUDIO_SEARCH_FANCY = 402; 4625702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4626702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int MEDIA_SCANNER = 500; 4627702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 46280027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen private static final int FS_ID = 600; 4629704a8b507b7aa61a09457075ed6f80c95914d731Marco Nelissen private static final int VERSION = 601; 46300027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen 463116dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood private static final int FILES = 700; 463216dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood private static final int FILES_ID = 701; 4633a36cfaef630ef5df7bef80b25f6bd493d040c7e4Brian Muramatsu 4634e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood // Used only by the MTP implementation 4635e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood private static final int MTP_OBJECTS = 702; 4636e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood private static final int MTP_OBJECTS_ID = 703; 4637e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood private static final int MTP_OBJECT_REFERENCES = 704; 4638819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood // UsbReceiver calls insert() and delete() with this URI to tell us 4639819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood // when MTP is connected and disconnected 4640819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood private static final int MTP_CONNECTED = 705; 4641b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 4642702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final UriMatcher URI_MATCHER = 4643702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project new UriMatcher(UriMatcher.NO_MATCH); 4644702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4645b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private static final String[] ID_PROJECTION = new String[] { 4646b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen MediaStore.MediaColumns._ID 4647b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen }; 4648b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 46491d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood private static final String[] PATH_PROJECTION = new String[] { 46501d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood MediaStore.MediaColumns._ID, 46511d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood MediaStore.MediaColumns.DATA, 46521d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood }; 46531d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood 4654702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final String[] MIME_TYPE_PROJECTION = new String[] { 4655702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.MediaColumns._ID, // 0 4656702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.MediaColumns.MIME_TYPE, // 1 4657702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project }; 4658702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4659b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private static final String[] READY_FLAG_PROJECTION = new String[] { 4660b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen MediaStore.MediaColumns._ID, 4661b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen MediaStore.MediaColumns.DATA, 4662b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen Images.Media.MINI_THUMB_MAGIC 4663b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen }; 4664b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 4665e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood private static final String OBJECT_REFERENCES_QUERY = 4666afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "SELECT " + Audio.Playlists.Members.AUDIO_ID + " FROM audio_playlists_map" 4667afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + " WHERE " + Audio.Playlists.Members.PLAYLIST_ID + "=?" 4668afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + " ORDER BY " + Audio.Playlists.Members.PLAY_ORDER; 4669e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood 4670702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project static 4671702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project { 4672702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/images/media", IMAGES_MEDIA); 4673702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/images/media/#", IMAGES_MEDIA_ID); 4674702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/images/thumbnails", IMAGES_THUMBNAILS); 4675702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/images/thumbnails/#", IMAGES_THUMBNAILS_ID); 4676702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4677702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/media", AUDIO_MEDIA); 4678702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/media/#", AUDIO_MEDIA_ID); 4679702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/media/#/genres", AUDIO_MEDIA_ID_GENRES); 4680702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/media/#/genres/#", AUDIO_MEDIA_ID_GENRES_ID); 4681702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/media/#/playlists", AUDIO_MEDIA_ID_PLAYLISTS); 4682702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/media/#/playlists/#", AUDIO_MEDIA_ID_PLAYLISTS_ID); 4683702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/genres", AUDIO_GENRES); 4684702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/genres/#", AUDIO_GENRES_ID); 4685702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/genres/#/members", AUDIO_GENRES_ID_MEMBERS); 4686bfbc30ff3b9e3a96b08c525d0971d8d8543ab000Marco Nelissen URI_MATCHER.addURI("media", "*/audio/genres/all/members", AUDIO_GENRES_ALL_MEMBERS); 4687702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/playlists", AUDIO_PLAYLISTS); 4688702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/playlists/#", AUDIO_PLAYLISTS_ID); 4689702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/playlists/#/members", AUDIO_PLAYLISTS_ID_MEMBERS); 4690702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/playlists/#/members/#", AUDIO_PLAYLISTS_ID_MEMBERS_ID); 4691702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/artists", AUDIO_ARTISTS); 4692702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/artists/#", AUDIO_ARTISTS_ID); 4693702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/artists/#/albums", AUDIO_ARTISTS_ID_ALBUMS); 4694702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/albums", AUDIO_ALBUMS); 4695702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/albums/#", AUDIO_ALBUMS_ID); 4696702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/albumart", AUDIO_ALBUMART); 4697702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/albumart/#", AUDIO_ALBUMART_ID); 469871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen URI_MATCHER.addURI("media", "*/audio/media/#/albumart", AUDIO_ALBUMART_FILE_ID); 4699702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4700702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/video/media", VIDEO_MEDIA); 4701702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/video/media/#", VIDEO_MEDIA_ID); 4702b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen URI_MATCHER.addURI("media", "*/video/thumbnails", VIDEO_THUMBNAILS); 4703b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen URI_MATCHER.addURI("media", "*/video/thumbnails/#", VIDEO_THUMBNAILS_ID); 4704702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4705702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/media_scanner", MEDIA_SCANNER); 4706702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 47070027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen URI_MATCHER.addURI("media", "*/fs_id", FS_ID); 4708704a8b507b7aa61a09457075ed6f80c95914d731Marco Nelissen URI_MATCHER.addURI("media", "*/version", VERSION); 47090027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen 4710819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood URI_MATCHER.addURI("media", "*/mtp_connected", MTP_CONNECTED); 4711819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood 4712702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*", VOLUMES_ID); 4713702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", null, VOLUMES); 4714702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4715b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood // Used by MTP implementation 471616dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood URI_MATCHER.addURI("media", "*/file", FILES); 471716dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood URI_MATCHER.addURI("media", "*/file/#", FILES_ID); 4718e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood URI_MATCHER.addURI("media", "*/object", MTP_OBJECTS); 4719e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood URI_MATCHER.addURI("media", "*/object/#", MTP_OBJECTS_ID); 4720e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood URI_MATCHER.addURI("media", "*/object/#/references", MTP_OBJECT_REFERENCES); 4721b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 4722a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen /** 4723a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen * @deprecated use the 'basic' or 'fancy' search Uris instead 4724a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen */ 4725702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/" + SearchManager.SUGGEST_URI_PATH_QUERY, 4726a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen AUDIO_SEARCH_LEGACY); 4727702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/" + SearchManager.SUGGEST_URI_PATH_QUERY + "/*", 4728a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen AUDIO_SEARCH_LEGACY); 4729a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen 4730a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // used for search suggestions 4731a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen URI_MATCHER.addURI("media", "*/audio/search/" + SearchManager.SUGGEST_URI_PATH_QUERY, 4732a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen AUDIO_SEARCH_BASIC); 4733a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen URI_MATCHER.addURI("media", "*/audio/search/" + SearchManager.SUGGEST_URI_PATH_QUERY + 4734a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "/*", AUDIO_SEARCH_BASIC); 4735a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen 4736a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // used by the music app's search activity 4737a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen URI_MATCHER.addURI("media", "*/audio/search/fancy", AUDIO_SEARCH_FANCY); 4738a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen URI_MATCHER.addURI("media", "*/audio/search/fancy/*", AUDIO_SEARCH_FANCY); 4739702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 474010af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen 474110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen @Override 474210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { 474310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen Collection<DatabaseHelper> foo = mDatabases.values(); 474410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen for (DatabaseHelper dbh: foo) { 474510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen StringBuilder s = new StringBuilder(); 474610af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen s.append(dbh.mName); 474710af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen s.append(": "); 474810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen SQLiteDatabase db = dbh.getReadableDatabase(); 474910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen if (db == null) { 475010af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen s.append("null"); 475110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen } else { 475210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen s.append("version " + db.getVersion() + ", "); 475310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen Cursor c = db.query("files", new String[] {"count(*)"}, null, null, null, null, null); 475410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen try { 475510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen if (c != null && c.moveToFirst()) { 475610af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen int num = c.getInt(0); 475710af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen s.append(num + " rows, "); 475810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen } else { 475910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen s.append("couldn't get row count, "); 476010af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen } 476110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen } finally { 476210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen if (c != null) { 476310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen c.close(); 476410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen } 476510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen } 476610af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen s.append(dbh.mNumInserts + " inserts, "); 476710af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen s.append(dbh.mNumUpdates + " updates, "); 476810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen s.append(dbh.mNumDeletes + " deletes, "); 476910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen s.append(dbh.mNumQueries + " queries, "); 477010af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen if (dbh.mScanStartTime != 0) { 477110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen s.append("scan started " + DateUtils.formatDateTime(getContext(), 477210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen dbh.mScanStartTime / 1000, 477310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen DateUtils.FORMAT_SHOW_DATE 477410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen | DateUtils.FORMAT_SHOW_TIME 477510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen | DateUtils.FORMAT_ABBREV_ALL)); 477610af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen if (dbh.mScanStopTime < dbh.mScanStartTime) { 477710af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen s.append(" (ongoing)"); 477810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen } else { 477910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen s.append(" (" + DateUtils.formatElapsedTime( 478010af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen (dbh.mScanStopTime - dbh.mScanStartTime) / 1000000) + ")"); 478110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen } 478210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen } 478310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen } 478410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen writer.println(s); 478510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen } 478610af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen if (mMediaScannerVolume != null) { 478710af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen writer.println("Scanning: " + mMediaScannerVolume); 478810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen } 478910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen } 479010af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen 4791702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project} 4792