MediaProvider.java revision 9311c7ff9d35ca3acc908da3da7a79fbf7a8da6b
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; 3590c7da0610b7c3f4d9f4f3b2767e0bae5f3ab258Marco Nelissenimport android.content.pm.PackageManager.NameNotFoundException; 3670676508bd3a081edd909875e141f2c48d79c1acDaniel Lehmannimport android.content.res.Resources; 37702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.database.Cursor; 38ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissenimport android.database.DatabaseUtils; 390027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissenimport android.database.MatrixCursor; 40702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.database.sqlite.SQLiteDatabase; 41702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.database.sqlite.SQLiteOpenHelper; 42702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.database.sqlite.SQLiteQueryBuilder; 43702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.graphics.Bitmap; 44702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.graphics.BitmapFactory; 45b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwoodimport android.media.MediaFile; 46702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.media.MediaScanner; 4738b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissenimport android.media.MediaScannerConnection; 4838b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissenimport android.media.MediaScannerConnection.MediaScannerConnectionClient; 49b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chenimport android.media.MiniThumbFile; 5090345783ad297da6059398cab174687de6f36a5bMike Lockwoodimport android.mtp.MtpConstants; 519be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwoodimport android.mtp.MtpStorage; 52702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.net.Uri; 53702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.Binder; 5438b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissenimport android.os.Bundle; 55702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.Environment; 56702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.FileUtils; 57702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.Handler; 58ab43e1853533e4d9352c251d53c36fb645077e43Chih-Chung Changimport android.os.HandlerThread; 59702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.Message; 60702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.ParcelFileDescriptor; 61702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.Process; 62d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwoodimport android.os.RemoteException; 6310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissenimport android.os.SystemClock; 644f2186758ee1c6eaa702bf1511b233b26143b631Mike Lockwoodimport android.os.SystemProperties; 65c47e4f2921312098eddc5fe49b080e0f2df60e81Mike Lockwoodimport android.os.storage.StorageManager; 661f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwoodimport android.os.storage.StorageVolume; 67ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwoodimport android.preference.PreferenceManager; 68702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.BaseColumns; 69702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.MediaStore; 70702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.MediaStore.Audio; 715bf5c26a3499d584332074baab97392696ed9614Ray Chenimport android.provider.MediaStore.Files; 7270676508bd3a081edd909875e141f2c48d79c1acDaniel Lehmannimport android.provider.MediaStore.Files.FileColumns; 73702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.MediaStore.Images; 7470676508bd3a081edd909875e141f2c48d79c1acDaniel Lehmannimport android.provider.MediaStore.Images.ImageColumns; 75702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.MediaStore.MediaColumns; 76702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.MediaStore.Video; 77702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.text.TextUtils; 7810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissenimport android.text.format.DateUtils; 79702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.util.Log; 80702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 81702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.io.File; 8210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissenimport java.io.FileDescriptor; 83702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.io.FileInputStream; 84702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.io.FileNotFoundException; 85702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.io.IOException; 86702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.io.OutputStream; 8710af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissenimport java.io.PrintWriter; 88702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.text.Collator; 89cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissenimport java.util.ArrayList; 9038b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissenimport java.util.Arrays; 9110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissenimport java.util.Collection; 92702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.util.HashMap; 93702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.util.HashSet; 94702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.util.Iterator; 95f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissenimport java.util.List; 9638b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissenimport java.util.Locale; 97b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chenimport java.util.PriorityQueue; 988a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huberimport java.util.Stack; 99702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 100166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissenimport libcore.io.ErrnoException; 101166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissenimport libcore.io.Libcore; 102166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen 103702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project/** 104702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Media content provider. See {@link android.provider.MediaStore} for details. 105702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Separate databases are kept for each external storage card we see (using the 106702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * card's ID as an index). The content visible at content://media/external/... 107702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * changes with the card. 108702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 109702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectpublic class MediaProvider extends ContentProvider { 110702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final Uri MEDIA_URI = Uri.parse("content://media"); 111702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final Uri ALBUMART_URI = Uri.parse("content://media/external/audio/albumart"); 112b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private static final int ALBUM_THUMB = 1; 113b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private static final int IMAGE_THUMB = 2; 114702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 115702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final HashMap<String, String> sArtistAlbumsMap = new HashMap<String, String>(); 116d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen private static final HashMap<String, String> sFolderArtMap = new HashMap<String, String>(); 117702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1187f36494e085c26c69cd5925e54028822025eff29Marco Nelissen // In memory cache of path<->id mappings, to speed up inserts during media scan 1197f36494e085c26c69cd5925e54028822025eff29Marco Nelissen HashMap<String, Long> mDirectoryCache = new HashMap<String, Long>(); 1207f36494e085c26c69cd5925e54028822025eff29Marco Nelissen 1218a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // A HashSet of paths that are pending creation of album art thumbnails. 1228a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber private HashSet mPendingThumbs = new HashSet(); 1238a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 1248a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // A Stack of outstanding thumbnail requests. 1258a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber private Stack mThumbRequestStack = new Stack(); 1268a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 12720434e032e498b716f87cce2f23dd646819218bfRay Chen // The lock of mMediaThumbQueue protects both mMediaThumbQueue and mCurrentThumbRequest. 12820434e032e498b716f87cce2f23dd646819218bfRay Chen private MediaThumbRequest mCurrentThumbRequest = null; 129b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private PriorityQueue<MediaThumbRequest> mMediaThumbQueue = 130b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen new PriorityQueue<MediaThumbRequest>(MediaThumbRequest.PRIORITY_NORMAL, 131b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen MediaThumbRequest.getComparator()); 132b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 133f7cc647081f0421c0247de275fa0754b29938c07Mike Lockwood private boolean mCaseInsensitivePaths; 1349be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood private static String[] mExternalStoragePaths; 13517ad80b32f839ccddac3911799ff732d1ca3a006Mike Lockwood 136a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // For compatibility with the approximately 0 apps that used mediaprovider search in 137a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // releases 1.0, 1.1 or 1.5 138a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen private String[] mSearchColsLegacy = new String[] { 139a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen android.provider.BaseColumns._ID, 140a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen MediaStore.Audio.Media.MIME_TYPE, 141a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "(CASE WHEN grouporder=1 THEN " + R.drawable.ic_search_category_music_artist + 142a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen " ELSE CASE WHEN grouporder=2 THEN " + R.drawable.ic_search_category_music_album + 143a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen " ELSE " + R.drawable.ic_search_category_music_song + " END END" + 144a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen ") AS " + SearchManager.SUGGEST_COLUMN_ICON_1, 145a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "0 AS " + SearchManager.SUGGEST_COLUMN_ICON_2, 146a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "text1 AS " + SearchManager.SUGGEST_COLUMN_TEXT_1, 147a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "text1 AS " + SearchManager.SUGGEST_COLUMN_QUERY, 148a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "CASE when grouporder=1 THEN data1 ELSE artist END AS data1", 149a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "CASE when grouporder=1 THEN data2 ELSE " + 150a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "CASE WHEN grouporder=2 THEN NULL ELSE album END END AS data2", 151a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "match as ar", 152a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen SearchManager.SUGGEST_COLUMN_INTENT_DATA, 153a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "grouporder", 154ea74c8add2d5b4215dfeb69183632d9e9797ac5aMarco Nelissen "NULL AS itemorder" // We should be sorting by the artist/album/title keys, but that 155ea74c8add2d5b4215dfeb69183632d9e9797ac5aMarco Nelissen // column is not available here, and the list is already sorted. 156a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen }; 157a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen private String[] mSearchColsFancy = new String[] { 158a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen android.provider.BaseColumns._ID, 159a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen MediaStore.Audio.Media.MIME_TYPE, 160a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen MediaStore.Audio.Artists.ARTIST, 161a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen MediaStore.Audio.Albums.ALBUM, 162a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen MediaStore.Audio.Media.TITLE, 163a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "data1", 164a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "data2", 165a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen }; 16663f748ff8b258d9110038778a006b3000164fbeeSatish Sampath // If this array gets changed, please update the constant below to point to the correct item. 167a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen private String[] mSearchColsBasic = new String[] { 168a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen android.provider.BaseColumns._ID, 169a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen MediaStore.Audio.Media.MIME_TYPE, 170a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "(CASE WHEN grouporder=1 THEN " + R.drawable.ic_search_category_music_artist + 171a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen " ELSE CASE WHEN grouporder=2 THEN " + R.drawable.ic_search_category_music_album + 172a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen " ELSE " + R.drawable.ic_search_category_music_song + " END END" + 173a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen ") AS " + SearchManager.SUGGEST_COLUMN_ICON_1, 174a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "text1 AS " + SearchManager.SUGGEST_COLUMN_TEXT_1, 175a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "text1 AS " + SearchManager.SUGGEST_COLUMN_QUERY, 17663f748ff8b258d9110038778a006b3000164fbeeSatish Sampath "(CASE WHEN grouporder=1 THEN '%1'" + // %1 gets replaced with localized string. 17763f748ff8b258d9110038778a006b3000164fbeeSatish Sampath " ELSE CASE WHEN grouporder=3 THEN artist || ' - ' || album" + 178e31cfb1a2c21e7ac7a646d40afbb48f49fab6907Marco Nelissen " ELSE CASE WHEN text2!='" + MediaStore.UNKNOWN_STRING + "' THEN text2" + 17963f748ff8b258d9110038778a006b3000164fbeeSatish Sampath " ELSE NULL END END END) AS " + SearchManager.SUGGEST_COLUMN_TEXT_2, 180a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen SearchManager.SUGGEST_COLUMN_INTENT_DATA 181a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen }; 18263f748ff8b258d9110038778a006b3000164fbeeSatish Sampath // Position of the TEXT_2 item in the above array. 18363f748ff8b258d9110038778a006b3000164fbeeSatish Sampath private final int SEARCH_COLUMN_BASIC_TEXT2 = 5; 184a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen 185a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen private static final String[] sMediaTableColumns = new String[] { 18616dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood FileColumns._ID, 187afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood FileColumns.MEDIA_TYPE, 1881717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood }; 1891717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood 1907f36494e085c26c69cd5925e54028822025eff29Marco Nelissen private static final String[] sIdOnlyColumn = new String[] { 1917f36494e085c26c69cd5925e54028822025eff29Marco Nelissen FileColumns._ID 1927f36494e085c26c69cd5925e54028822025eff29Marco Nelissen }; 1937f36494e085c26c69cd5925e54028822025eff29Marco Nelissen 194166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen private static final String[] sDataOnlyColumn = new String[] { 195166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen FileColumns.DATA 196166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen }; 197166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen 198a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen private static final String[] sMediaTypeDataId = new String[] { 199a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen FileColumns.MEDIA_TYPE, 200a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen FileColumns.DATA, 201a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen FileColumns._ID 202a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen}; 203a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen 204a9c4e330dacb37cfffa9c00f7da83cafde4accefMarco Nelissen private Uri mAlbumArtBaseUri = Uri.parse("content://media/external/audio/albumart"); 205a9c4e330dacb37cfffa9c00f7da83cafde4accefMarco Nelissen 206702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private BroadcastReceiver mUnmountReceiver = new BroadcastReceiver() { 207702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 208702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public void onReceive(Context context, Intent intent) { 209702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (intent.getAction().equals(Intent.ACTION_MEDIA_EJECT)) { 2101f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood StorageVolume storage = (StorageVolume)intent.getParcelableExtra( 2111f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood StorageVolume.EXTRA_STORAGE_VOLUME); 2121f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood // If primary external storage is ejected, then remove the external volume 2131f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood // notify all cursors backed by data on that volume. 2141f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood if (storage.getPath().equals(mExternalStoragePaths[0])) { 2151f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood detachVolume(Uri.parse("content://media/external")); 2161f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood sFolderArtMap.clear(); 2171f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood MiniThumbFile.reset(); 2181f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood } else { 2191f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood // If secondary external storage is ejected, then we delete all database 2201f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood // entries for that storage from the files table. 2211f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood synchronized (mDatabases) { 2221f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood DatabaseHelper database = mDatabases.get(EXTERNAL_VOLUME); 2231f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood Uri uri = Uri.parse("file://" + storage.getPath()); 2241f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood if (database != null) { 2251f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood try { 2261f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood // Send media scanner started and stopped broadcasts for apps that rely 2271f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood // on these Intents for coarse grained media database notifications. 2281f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood context.sendBroadcast( 2291f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood new Intent(Intent.ACTION_MEDIA_SCANNER_STARTED, uri)); 2301f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood 2311f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood // don't send objectRemoved events - MTP be sending StorageRemoved anyway 2321f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood mDisableMtpObjectCallbacks = true; 2331f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood Log.d(TAG, "deleting all entries for storage " + storage); 2341f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood SQLiteDatabase db = database.getWritableDatabase(); 2354b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood // First clear the file path to disable the _DELETE_FILE database hook. 2364b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood // We do this to avoid deleting files if the volume is remounted while 2374b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood // we are still processing the unmount event. 2384b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood ContentValues values = new ContentValues(); 2394b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood values.put(Files.FileColumns.DATA, ""); 2404b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood String where = FileColumns.STORAGE_ID + "=?"; 2414b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood String[] whereArgs = new String[] { Integer.toString(storage.getStorageId()) }; 2424b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood db.update("files", values, where, whereArgs); 2434b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood // now delete the records 2444b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood db.delete("files", where, whereArgs); 2454b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood // notify on media Uris as well as the files Uri 2464b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood context.getContentResolver().notifyChange( 2474b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood Audio.Media.getContentUri(EXTERNAL_VOLUME), null); 2484b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood context.getContentResolver().notifyChange( 2494b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood Images.Media.getContentUri(EXTERNAL_VOLUME), null); 2504b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood context.getContentResolver().notifyChange( 2514b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood Video.Media.getContentUri(EXTERNAL_VOLUME), null); 2521f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood context.getContentResolver().notifyChange( 2531f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood Files.getContentUri(EXTERNAL_VOLUME), null); 2541f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood } catch (Exception e) { 2551f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood Log.e(TAG, "exception deleting storage entries", e); 2561f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood } finally { 2571f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood context.sendBroadcast( 2581f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood new Intent(Intent.ACTION_MEDIA_SCANNER_FINISHED, uri)); 2591f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood mDisableMtpObjectCallbacks = false; 2601f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood } 2611f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood } 2621f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood } 2631f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood } 264702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 265702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 266702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project }; 267702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 268d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood // set to disable sending events when the operation originates from MTP 269d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood private boolean mDisableMtpObjectCallbacks; 270d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 271d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood private final SQLiteDatabase.CustomFunction mObjectRemovedCallback = 272d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood new SQLiteDatabase.CustomFunction() { 273d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood public void callback(String[] args) { 2747f36494e085c26c69cd5925e54028822025eff29Marco Nelissen // We could remove only the deleted entry from the cache, but that 2757f36494e085c26c69cd5925e54028822025eff29Marco Nelissen // requires the path, which we don't have here, so instead we just 2767f36494e085c26c69cd5925e54028822025eff29Marco Nelissen // clear the entire cache. 2777f36494e085c26c69cd5925e54028822025eff29Marco Nelissen // TODO: include the path in the callback and only remove the affected 2787f36494e085c26c69cd5925e54028822025eff29Marco Nelissen // entry from the cache 2797f36494e085c26c69cd5925e54028822025eff29Marco Nelissen mDirectoryCache.clear(); 280d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood // do nothing if the operation originated from MTP 281d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood if (mDisableMtpObjectCallbacks) return; 282d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 283d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood Log.d(TAG, "object removed " + args[0]); 284d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood IMtpService mtpService = mMtpService; 285d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood if (mtpService != null) { 286d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood try { 287d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood sendObjectRemoved(Integer.parseInt(args[0])); 288d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } catch (NumberFormatException e) { 289d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood Log.e(TAG, "NumberFormatException in mObjectRemovedCallback", e); 290d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 291d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 292d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 293d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood }; 294d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 295702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 296702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Wrapper class for a specific database (associated with one particular 297702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * external card, or with internal storage). Can open the actual database 298702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * on demand, create and upgrade the schema, etc. 299702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 300fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn static final class DatabaseHelper extends SQLiteOpenHelper { 301702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final Context mContext; 3025524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood final String mName; 303702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final boolean mInternal; // True if this is the internal database 304fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn final boolean mEarlyUpgrade; 305fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn final SQLiteDatabase.CustomFunction mObjectRemovedCallback; 3065524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood boolean mUpgradeAttempted; // Used for upgrade error handling 30710af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen int mNumQueries; 30810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen int mNumUpdates; 30910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen int mNumInserts; 31010af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen int mNumDeletes; 31110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen long mScanStartTime; 31210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen long mScanStopTime; 313702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 314702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // In memory caches of artist and album data. 315702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project HashMap<String, Long> mArtistCache = new HashMap<String, Long>(); 316702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project HashMap<String, Long> mAlbumCache = new HashMap<String, Long>(); 317702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 318fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn public DatabaseHelper(Context context, String name, boolean internal, 319fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn boolean earlyUpgrade, 320fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn SQLiteDatabase.CustomFunction objectRemovedCallback) { 32190c7da0610b7c3f4d9f4f3b2767e0bae5f3ab258Marco Nelissen super(context, name, null, getDatabaseVersion(context)); 322702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mContext = context; 3235524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood mName = name; 324702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mInternal = internal; 325fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn mEarlyUpgrade = earlyUpgrade; 326fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn mObjectRemovedCallback = objectRemovedCallback; 327702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 328702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 329702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 330702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Creates database the first time we try to open it. 331702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 332702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 333702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public void onCreate(final SQLiteDatabase db) { 33490c7da0610b7c3f4d9f4f3b2767e0bae5f3ab258Marco Nelissen updateDatabase(mContext, db, mInternal, 0, getDatabaseVersion(mContext)); 335702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 336702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 337702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 338702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Updates the database format when a new content provider is used 339702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * with an older database format. 340702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 341702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 342702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public void onUpgrade(final SQLiteDatabase db, final int oldV, final int newV) { 3435524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood mUpgradeAttempted = true; 34490c7da0610b7c3f4d9f4f3b2767e0bae5f3ab258Marco Nelissen updateDatabase(mContext, db, mInternal, oldV, newV); 345702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 346702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 347db8357b2b2888ce3778278e9cd9e698347ca6105Owen Lin @Override 348db8357b2b2888ce3778278e9cd9e698347ca6105Owen Lin public synchronized SQLiteDatabase getWritableDatabase() { 3495524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood SQLiteDatabase result = null; 3505524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood mUpgradeAttempted = false; 3515524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood try { 3525524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood result = super.getWritableDatabase(); 3535524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood } catch (Exception e) { 3545524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood if (!mUpgradeAttempted) { 3555524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood Log.e(TAG, "failed to open database " + mName, e); 3565524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood return null; 3575524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood } 3585524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood } 3595524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood 3605524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood // If we failed to open the database during an upgrade, delete the file and try again. 3615524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood // This will result in the creation of a fresh database, which will be repopulated 3625524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood // when the media scanner runs. 3635524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood if (result == null && mUpgradeAttempted) { 3645524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood mContext.getDatabasePath(mName).delete(); 3655524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood result = super.getWritableDatabase(); 3665524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood } 3675524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood return result; 3685524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood } 3695524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood 370702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 371993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood * For devices that have removable storage, we support keeping multiple databases 372993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood * to allow users to switch between a number of cards. 373993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood * On such devices, touch this particular database and garbage collect old databases. 374702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * An LRU cache system is used to clean up databases for old external 375702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * storage volumes. 376702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 377702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 378702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public void onOpen(SQLiteDatabase db) { 37936d7136bebac6ea5738fb653a74dcd6c71e4cd58Dmitry Dolinsky 380652c337bac290c7dfcde8725e7c771193a7f7ed6Vasu Nori // Turn on WAL optimization 381652c337bac290c7dfcde8725e7c771193a7f7ed6Vasu Nori db.enableWriteAheadLogging(); 38236d7136bebac6ea5738fb653a74dcd6c71e4cd58Dmitry Dolinsky 383702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (mInternal) return; // The internal database is kept separately. 384702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 385fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn if (mEarlyUpgrade) return; // Doing early upgrade. 386fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn 387fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn if (mObjectRemovedCallback != null) { 388fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn db.addCustomFunction("_OBJECT_REMOVED", 1, mObjectRemovedCallback); 389fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn } 390d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 391993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood // the code below is only needed on devices with removable storage 392993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood if (!Environment.isExternalStorageRemovable()) return; 393993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood 394702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // touch the database file to show it is most recently used 395702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File file = new File(db.getPath()); 396702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long now = System.currentTimeMillis(); 397702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project file.setLastModified(now); 398702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 399702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // delete least recently used databases if we are over the limit 400702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String[] databases = mContext.databaseList(); 401702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int count = databases.length; 402702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int limit = MAX_EXTERNAL_DATABASES; 403702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 404702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // delete external databases that have not been used in the past two months 405702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long twoMonthsAgo = now - OBSOLETE_DATABASE_DB; 406702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project for (int i = 0; i < databases.length; i++) { 407702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File other = mContext.getDatabasePath(databases[i]); 408702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (INTERNAL_DATABASE_NAME.equals(databases[i]) || file.equals(other)) { 409702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project databases[i] = null; 410702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count--; 411702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (file.equals(other)) { 412702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // reduce limit to account for the existence of the database we 413702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // are about to open, which we removed from the list. 414702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project limit--; 415702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 416702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 417702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long time = other.lastModified(); 418702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (time < twoMonthsAgo) { 419702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (LOCAL_LOGV) Log.v(TAG, "Deleting old database " + databases[i]); 420702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mContext.deleteDatabase(databases[i]); 421702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project databases[i] = null; 422702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count--; 423702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 424702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 425702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 426702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 427702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // delete least recently used databases until 428702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // we are no longer over the limit 429702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project while (count > limit) { 430702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int lruIndex = -1; 431702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long lruTime = 0; 432702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 433702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project for (int i = 0; i < databases.length; i++) { 434702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (databases[i] != null) { 435702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long time = mContext.getDatabasePath(databases[i]).lastModified(); 436702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (lruTime == 0 || time < lruTime) { 437702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project lruIndex = i; 438702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project lruTime = time; 439702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 440702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 441702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 442702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 443702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // delete least recently used database 444702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (lruIndex != -1) { 445702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (LOCAL_LOGV) Log.v(TAG, "Deleting old database " + databases[lruIndex]); 446702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mContext.deleteDatabase(databases[lruIndex]); 447702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project databases[lruIndex] = null; 448702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count--; 449702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 450702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 451702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 452702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 453702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 45434be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood // synchronize on mMtpServiceConnection when accessing mMtpService 455d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood private IMtpService mMtpService; 456d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 457d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood private final ServiceConnection mMtpServiceConnection = new ServiceConnection() { 458d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood public void onServiceConnected(ComponentName className, android.os.IBinder service) { 45934be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood synchronized (this) { 46034be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood mMtpService = IMtpService.Stub.asInterface(service); 46134be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood } 462d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 463d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 464d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood public void onServiceDisconnected(ComponentName className) { 46534be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood synchronized (this) { 46634be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood mMtpService = null; 46734be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood } 468d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 469d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood }; 470d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 471ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood private static final String[] sDefaultFolderNames = { 472ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood Environment.DIRECTORY_MUSIC, 473ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood Environment.DIRECTORY_PODCASTS, 474ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood Environment.DIRECTORY_RINGTONES, 475ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood Environment.DIRECTORY_ALARMS, 476ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood Environment.DIRECTORY_NOTIFICATIONS, 477ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood Environment.DIRECTORY_PICTURES, 478ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood Environment.DIRECTORY_MOVIES, 479ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood Environment.DIRECTORY_DOWNLOADS, 480ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood Environment.DIRECTORY_DCIM, 481ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood }; 482ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood 483ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood // creates default folders (Music, Downloads, etc) 48410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen private void createDefaultFolders(DatabaseHelper helper, SQLiteDatabase db) { 485ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood // Use a SharedPreference to ensure we only do this once. 486ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood // We don't want to annoy the user by recreating the directories 487ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood // after she has deleted them. 488ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext()); 489ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood if (prefs.getInt("created_default_folders", 0) == 0) { 490ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood for (String folderName : sDefaultFolderNames) { 491ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood File file = Environment.getExternalStoragePublicDirectory(folderName); 492ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood if (!file.exists()) { 493ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood file.mkdirs(); 49410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen insertDirectory(helper, db, file.getAbsolutePath()); 495ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood } 496ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood } 497ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood 498ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood SharedPreferences.Editor e = prefs.edit(); 499ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood e.clear(); 500ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood e.putInt("created_default_folders", 1); 501ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood e.commit(); 502ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood } 503ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood } 504ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood 5059311c7ff9d35ca3acc908da3da7a79fbf7a8da6bMarco Nelissen public static int getDatabaseVersion(Context context) { 50690c7da0610b7c3f4d9f4f3b2767e0bae5f3ab258Marco Nelissen try { 50790c7da0610b7c3f4d9f4f3b2767e0bae5f3ab258Marco Nelissen return context.getPackageManager().getPackageInfo( 50890c7da0610b7c3f4d9f4f3b2767e0bae5f3ab258Marco Nelissen context.getPackageName(), 0).versionCode; 50990c7da0610b7c3f4d9f4f3b2767e0bae5f3ab258Marco Nelissen } catch (NameNotFoundException e) { 51090c7da0610b7c3f4d9f4f3b2767e0bae5f3ab258Marco Nelissen throw new RuntimeException("couldn't get version code for " + context); 51190c7da0610b7c3f4d9f4f3b2767e0bae5f3ab258Marco Nelissen } 51290c7da0610b7c3f4d9f4f3b2767e0bae5f3ab258Marco Nelissen } 51390c7da0610b7c3f4d9f4f3b2767e0bae5f3ab258Marco Nelissen 514702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 515702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public boolean onCreate() { 516d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood final Context context = getContext(); 517d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 518acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen sArtistAlbumsMap.put(MediaStore.Audio.Albums._ID, "audio.album_id AS " + 519acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen MediaStore.Audio.Albums._ID); 520702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Albums.ALBUM, "album"); 521702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Albums.ALBUM_KEY, "album_key"); 522acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen sArtistAlbumsMap.put(MediaStore.Audio.Albums.FIRST_YEAR, "MIN(year) AS " + 523702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.Audio.Albums.FIRST_YEAR); 524acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen sArtistAlbumsMap.put(MediaStore.Audio.Albums.LAST_YEAR, "MAX(year) AS " + 525702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.Audio.Albums.LAST_YEAR); 526702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Media.ARTIST, "artist"); 527702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Media.ARTIST_ID, "artist"); 528702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Media.ARTIST_KEY, "artist_key"); 529acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen sArtistAlbumsMap.put(MediaStore.Audio.Albums.NUMBER_OF_SONGS, "count(*) AS " + 530acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen MediaStore.Audio.Albums.NUMBER_OF_SONGS); 531acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen sArtistAlbumsMap.put(MediaStore.Audio.Albums.ALBUM_ART, "album_art._data AS " + 532acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen MediaStore.Audio.Albums.ALBUM_ART); 533702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 53463f748ff8b258d9110038778a006b3000164fbeeSatish Sampath mSearchColsBasic[SEARCH_COLUMN_BASIC_TEXT2] = 53563f748ff8b258d9110038778a006b3000164fbeeSatish Sampath mSearchColsBasic[SEARCH_COLUMN_BASIC_TEXT2].replaceAll( 536d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood "%1", context.getString(R.string.artist_label)); 537702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mDatabases = new HashMap<String, DatabaseHelper>(); 538702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project attachVolume(INTERNAL_VOLUME); 539702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 540702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project IntentFilter iFilter = new IntentFilter(Intent.ACTION_MEDIA_EJECT); 541702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project iFilter.addDataScheme("file"); 542d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood context.registerReceiver(mUnmountReceiver, iFilter); 543702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 5447d4f72d8ab71e28e9d40da87ec8c75ded254dd08Dianne Hackborn mCaseInsensitivePaths = true; 5454f2186758ee1c6eaa702bf1511b233b26143b631Mike Lockwood 546c47e4f2921312098eddc5fe49b080e0f2df60e81Mike Lockwood StorageManager storageManager = 547c47e4f2921312098eddc5fe49b080e0f2df60e81Mike Lockwood (StorageManager)context.getSystemService(Context.STORAGE_SERVICE); 548c47e4f2921312098eddc5fe49b080e0f2df60e81Mike Lockwood mExternalStoragePaths = storageManager.getVolumePaths(); 5499be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood 550702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // open external database if external storage is mounted 551702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String state = Environment.getExternalStorageState(); 552702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (Environment.MEDIA_MOUNTED.equals(state) || 553702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) { 554702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project attachVolume(EXTERNAL_VOLUME); 555702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 556702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 557ab43e1853533e4d9352c251d53c36fb645077e43Chih-Chung Chang HandlerThread ht = new HandlerThread("thumbs thread", Process.THREAD_PRIORITY_BACKGROUND); 558ab43e1853533e4d9352c251d53c36fb645077e43Chih-Chung Chang ht.start(); 559ab43e1853533e4d9352c251d53c36fb645077e43Chih-Chung Chang mThumbHandler = new Handler(ht.getLooper()) { 560702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 561702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public void handleMessage(Message msg) { 562b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (msg.what == IMAGE_THUMB) { 563b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen synchronized (mMediaThumbQueue) { 56420434e032e498b716f87cce2f23dd646819218bfRay Chen mCurrentThumbRequest = mMediaThumbQueue.poll(); 565b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 56620434e032e498b716f87cce2f23dd646819218bfRay Chen if (mCurrentThumbRequest == null) { 567b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen Log.w(TAG, "Have message but no request?"); 568b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } else { 569b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen try { 57020434e032e498b716f87cce2f23dd646819218bfRay Chen File origFile = new File(mCurrentThumbRequest.mPath); 5714d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen if (origFile.exists() && origFile.length() > 0) { 57220434e032e498b716f87cce2f23dd646819218bfRay Chen mCurrentThumbRequest.execute(); 5734d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen } else { 5744d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen // original file hasn't been stored yet 5754d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen synchronized (mMediaThumbQueue) { 57620434e032e498b716f87cce2f23dd646819218bfRay Chen Log.w(TAG, "original file hasn't been stored yet: " + mCurrentThumbRequest.mPath); 5774d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen } 5784d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen } 579b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } catch (IOException ex) { 5801d6eba9e1e28c722aa73a651d86a2efe2b937bf2Ray Chen Log.w(TAG, ex); 5811d6eba9e1e28c722aa73a651d86a2efe2b937bf2Ray Chen } catch (UnsupportedOperationException ex) { 5821d6eba9e1e28c722aa73a651d86a2efe2b937bf2Ray Chen // This could happen if we unplug the sd card during insert/update/delete 5831d6eba9e1e28c722aa73a651d86a2efe2b937bf2Ray Chen // See getDatabaseForUri. 5841d6eba9e1e28c722aa73a651d86a2efe2b937bf2Ray Chen Log.w(TAG, ex); 58522c5095b70a9fd6304fcf2366e8e40e37ae95764Erik Rydgren } catch (OutOfMemoryError err) { 58622c5095b70a9fd6304fcf2366e8e40e37ae95764Erik Rydgren /* 58722c5095b70a9fd6304fcf2366e8e40e37ae95764Erik Rydgren * Note: Catching Errors is in most cases considered 58822c5095b70a9fd6304fcf2366e8e40e37ae95764Erik Rydgren * bad practice. However, in this case it is 58922c5095b70a9fd6304fcf2366e8e40e37ae95764Erik Rydgren * motivated by the fact that corrupt or very large 59022c5095b70a9fd6304fcf2366e8e40e37ae95764Erik Rydgren * images may cause a huge allocation to be 59122c5095b70a9fd6304fcf2366e8e40e37ae95764Erik Rydgren * requested and denied. The bitmap handling API in 59222c5095b70a9fd6304fcf2366e8e40e37ae95764Erik Rydgren * Android offers no other way to guard against 59322c5095b70a9fd6304fcf2366e8e40e37ae95764Erik Rydgren * these problems than by catching OutOfMemoryError. 59422c5095b70a9fd6304fcf2366e8e40e37ae95764Erik Rydgren */ 59522c5095b70a9fd6304fcf2366e8e40e37ae95764Erik Rydgren Log.w(TAG, err); 596b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } finally { 59720434e032e498b716f87cce2f23dd646819218bfRay Chen synchronized (mCurrentThumbRequest) { 59820434e032e498b716f87cce2f23dd646819218bfRay Chen mCurrentThumbRequest.mState = MediaThumbRequest.State.DONE; 59920434e032e498b716f87cce2f23dd646819218bfRay Chen mCurrentThumbRequest.notifyAll(); 600b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 601b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 602b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 603b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } else if (msg.what == ALBUM_THUMB) { 604b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen ThumbData d; 605b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen synchronized (mThumbRequestStack) { 606b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen d = (ThumbData)mThumbRequestStack.pop(); 607b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 6088a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 609b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen makeThumbInternal(d); 610b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen synchronized (mPendingThumbs) { 611b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen mPendingThumbs.remove(d.path); 612b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 6138a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 614702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 615702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project }; 616702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 617702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return true; 618702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 619702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 620afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood private static final String IMAGE_COLUMNS = 621afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "_data,_size,_display_name,mime_type,title,date_added," + 622afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "date_modified,description,picasa_id,isprivate,latitude,longitude," + 623bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang "datetaken,orientation,mini_thumb_magic,bucket_id,bucket_display_name," + 624bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang "width,height"; 625bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang 626bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang private static final String IMAGE_COLUMNSv407 = 627bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang "_data,_size,_display_name,mime_type,title,date_added," + 628bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang "date_modified,description,picasa_id,isprivate,latitude,longitude," + 629afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "datetaken,orientation,mini_thumb_magic,bucket_id,bucket_display_name"; 630afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 631805b0b734dd5a73e2f77cd8d818a07a8627a8c1eMarco Nelissen private static final String AUDIO_COLUMNSv99 = 632afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "_data,_display_name,_size,mime_type,date_added," + 633afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "date_modified,title,title_key,duration,artist_id,composer,album_id," + 634afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "track,year,is_ringtone,is_music,is_alarm,is_notification,is_podcast," + 635afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "bookmark"; 636afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 637805b0b734dd5a73e2f77cd8d818a07a8627a8c1eMarco Nelissen private static final String AUDIO_COLUMNSv100 = 638805b0b734dd5a73e2f77cd8d818a07a8627a8c1eMarco Nelissen "_data,_display_name,_size,mime_type,date_added," + 639805b0b734dd5a73e2f77cd8d818a07a8627a8c1eMarco Nelissen "date_modified,title,title_key,duration,artist_id,composer,album_id," + 640805b0b734dd5a73e2f77cd8d818a07a8627a8c1eMarco Nelissen "track,year,is_ringtone,is_music,is_alarm,is_notification,is_podcast," + 641805b0b734dd5a73e2f77cd8d818a07a8627a8c1eMarco Nelissen "bookmark,album_artist"; 642805b0b734dd5a73e2f77cd8d818a07a8627a8c1eMarco Nelissen 643957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang private static final String AUDIO_COLUMNSv405 = 644957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang "_data,_display_name,_size,mime_type,date_added,is_drm," + 645957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang "date_modified,title,title_key,duration,artist_id,composer,album_id," + 646957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang "track,year,is_ringtone,is_music,is_alarm,is_notification,is_podcast," + 647957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang "bookmark,album_artist"; 648957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang 649afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood private static final String VIDEO_COLUMNS = 650afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "_data,_display_name,_size,mime_type,date_added,date_modified," + 651afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "title,duration,artist,album,resolution,description,isprivate,tags," + 652afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "category,language,mini_thumb_data,latitude,longitude,datetaken," + 653bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang "mini_thumb_magic,bucket_id,bucket_display_name,bookmark,width," + 654bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang "height"; 655bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang 656bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang private static final String VIDEO_COLUMNSv407 = 657bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang "_data,_display_name,_size,mime_type,date_added,date_modified," + 658bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang "title,duration,artist,album,resolution,description,isprivate,tags," + 659bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang "category,language,mini_thumb_data,latitude,longitude,datetaken," + 660afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "mini_thumb_magic,bucket_id,bucket_display_name, bookmark"; 661afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 662afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood private static final String PLAYLIST_COLUMNS = "_data,name,date_added,date_modified"; 663afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 664702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 665702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * This method takes care of updating all the tables in the database to the 666702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * current version, creating them if necessary. 667702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * This method can only update databases at schema 63 or higher, which was 668702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * created August 1, 2008. Older database will be cleared and recreated. 669702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param db Database 670702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param internal True if this is the internal media database 671702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 67290c7da0610b7c3f4d9f4f3b2767e0bae5f3ab258Marco Nelissen private static void updateDatabase(Context context, SQLiteDatabase db, boolean internal, 673702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int fromVersion, int toVersion) { 674702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 675702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // sanity checks 67690c7da0610b7c3f4d9f4f3b2767e0bae5f3ab258Marco Nelissen int dbversion = getDatabaseVersion(context); 67790c7da0610b7c3f4d9f4f3b2767e0bae5f3ab258Marco Nelissen if (toVersion != dbversion) { 67890c7da0610b7c3f4d9f4f3b2767e0bae5f3ab258Marco Nelissen Log.e(TAG, "Illegal update request. Got " + toVersion + ", expected " + dbversion); 679702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalArgumentException(); 680702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else if (fromVersion > toVersion) { 68195ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen Log.e(TAG, "Illegal update request: can't downgrade from " + fromVersion + 682702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " to " + toVersion + ". Did you forget to wipe data?"); 683702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalArgumentException(); 684702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 685702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 686d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood // Revisions 84-86 were a failed attempt at supporting the "album artist" id3 tag. 687acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // We can't downgrade from those revisions, so start over. 688022eb71bfe8ec65b8817eaa432a530194210ec23Marco Nelissen // (the initial change to do this was wrong, so now we actually need to start over 689022eb71bfe8ec65b8817eaa432a530194210ec23Marco Nelissen // if the database version is 84-89) 690bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin // Post-gingerbread, revisions 91-94 were broken in a way that is not easy to repair. 691bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin // However version 91 was reused in a divergent development path for gingerbread, 692bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin // so we need to support upgrades from 91. 693bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin // Therefore we will only force a reset for versions 92 - 94. 694d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood if (fromVersion < 63 || (fromVersion >= 84 && fromVersion <= 89) || 695bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin (fromVersion >= 92 && fromVersion <= 94)) { 696702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Drop everything and start over. 697702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Log.i(TAG, "Upgrading media database from version " + 698702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project fromVersion + " to " + toVersion + ", which will destroy all old data"); 699d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen fromVersion = 63; 700702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS images"); 701702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS images_cleanup"); 702702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS thumbnails"); 703702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS thumbnails_cleanup"); 704702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS audio_meta"); 705702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS artists"); 706702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS albums"); 707702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS album_art"); 708702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP VIEW IF EXISTS artist_info"); 709702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP VIEW IF EXISTS album_info"); 710702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP VIEW IF EXISTS artists_albums_map"); 711702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS audio_meta_cleanup"); 712702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS audio_genres"); 713702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS audio_genres_map"); 714702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS audio_genres_cleanup"); 715702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS audio_playlists"); 716702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS audio_playlists_map"); 717702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS audio_playlists_cleanup"); 718702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS albumart_cleanup1"); 719702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS albumart_cleanup2"); 720702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS video"); 721702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS video_cleanup"); 722cec8df8a90209fc4df5d1ff5f02dc364d0d2edc6Mike Lockwood db.execSQL("DROP TABLE IF EXISTS objects"); 7239ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood db.execSQL("DROP TRIGGER IF EXISTS images_objects_cleanup"); 7249ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood db.execSQL("DROP TRIGGER IF EXISTS audio_objects_cleanup"); 7259ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood db.execSQL("DROP TRIGGER IF EXISTS video_objects_cleanup"); 7269ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood db.execSQL("DROP TRIGGER IF EXISTS playlists_objects_cleanup"); 727702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 728702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS images (" + 729702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 730702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_data TEXT," + 731702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_size INTEGER," + 732702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_display_name TEXT," + 733702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "mime_type TEXT," + 734702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "title TEXT," + 735702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_added INTEGER," + 736702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_modified INTEGER," + 737702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "description TEXT," + 738702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "picasa_id TEXT," + 739702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "isprivate INTEGER," + 740702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "latitude DOUBLE," + 741702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "longitude DOUBLE," + 742702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "datetaken INTEGER," + 743702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "orientation INTEGER," + 744702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "mini_thumb_magic INTEGER," + 745702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "bucket_id TEXT," + 746702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "bucket_display_name TEXT" + 747702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 748702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 749702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE INDEX IF NOT EXISTS mini_thumb_magic_index on images(mini_thumb_magic);"); 750702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 751702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS images_cleanup DELETE ON images " + 752702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 753702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE FROM thumbnails WHERE image_id = old._id;" + 754702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT _DELETE_FILE(old._data);" + 755702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 756702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 757b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // create image thumbnail table 758702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS thumbnails (" + 759702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 760702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_data TEXT," + 761702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "image_id INTEGER," + 762702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "kind INTEGER," + 763702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "width INTEGER," + 764702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "height INTEGER" + 765702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 766702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 767702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE INDEX IF NOT EXISTS image_id_index on thumbnails(image_id);"); 768702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 769702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS thumbnails_cleanup DELETE ON thumbnails " + 770702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 771702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT _DELETE_FILE(old._data);" + 772702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 773702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 774702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains meta data about audio files 775702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS audio_meta (" + 776702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 777216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen "_data TEXT UNIQUE NOT NULL," + 778702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_display_name TEXT," + 779702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_size INTEGER," + 780702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "mime_type TEXT," + 781702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_added INTEGER," + 782702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_modified INTEGER," + 783702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "title TEXT NOT NULL," + 784702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "title_key TEXT NOT NULL," + 785702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "duration INTEGER," + 786702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "artist_id INTEGER," + 787702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "composer TEXT," + 788702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "album_id INTEGER," + 789702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "track INTEGER," + // track is an integer to allow proper sorting 790702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "year INTEGER CHECK(year!=0)," + 791702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "is_ringtone INTEGER," + 792702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "is_music INTEGER," + 793702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "is_alarm INTEGER," + 794702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "is_notification INTEGER" + 795702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 796702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 797702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains a sort/group "key" and the preferred display name for artists 798702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS artists (" + 799702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "artist_id INTEGER PRIMARY KEY," + 800702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "artist_key TEXT NOT NULL UNIQUE," + 801702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "artist TEXT NOT NULL" + 802702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 803702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 804702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains a sort/group "key" and the preferred display name for albums 805702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS albums (" + 806702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "album_id INTEGER PRIMARY KEY," + 807702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "album_key TEXT NOT NULL UNIQUE," + 808702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "album TEXT NOT NULL" + 809702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 810702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 811702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS album_art (" + 812702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "album_id INTEGER PRIMARY KEY," + 813702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_data TEXT" + 814702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 815702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 816702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project recreateAudioView(db); 81795ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen 818702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 819702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Provides some extra info about artists, like the number of tracks 820702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // and albums for this artist 821702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE VIEW IF NOT EXISTS artist_info AS " + 822702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT artist_id AS _id, artist, artist_key, " + 823acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen "COUNT(DISTINCT album) AS number_of_albums, " + 824702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "COUNT(*) AS number_of_tracks FROM audio WHERE is_music=1 "+ 825702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "GROUP BY artist_key;"); 826702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 827702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Provides extra info albums, such as the number of tracks 828702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE VIEW IF NOT EXISTS album_info AS " + 829702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT audio.album_id AS _id, album, album_key, " + 830702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "MIN(year) AS minyear, " + 831702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "MAX(year) AS maxyear, artist, artist_id, artist_key, " + 832702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "count(*) AS " + MediaStore.Audio.Albums.NUMBER_OF_SONGS + 833702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ",album_art._data AS album_art" + 834702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " FROM audio LEFT OUTER JOIN album_art ON audio.album_id=album_art.album_id" + 835702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " WHERE is_music=1 GROUP BY audio.album_id;"); 836702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 837acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // For a given artist_id, provides the album_id for albums on 838acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // which the artist appears. 839acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("CREATE VIEW IF NOT EXISTS artists_albums_map AS " + 840acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen "SELECT DISTINCT artist_id, album_id FROM audio_meta;"); 841acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen 842702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /* 843702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Only external media volumes can handle genres, playlists, etc. 844702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 845702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!internal) { 846702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Cleans up when an audio file is deleted 847702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS audio_meta_cleanup DELETE ON audio_meta " + 848702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 849702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE FROM audio_genres_map WHERE audio_id = old._id;" + 850702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE FROM audio_playlists_map WHERE audio_id = old._id;" + 851702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 852702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 853702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains audio genre definitions 854702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS audio_genres (" + 855702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 856702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "name TEXT NOT NULL" + 857702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 858702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 85978b2885edc406273d688536b0eadfea006b20662Marco Nelissen // Contains mappings between audio genres and audio files 860702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS audio_genres_map (" + 861702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 862702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_id INTEGER NOT NULL," + 863702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "genre_id INTEGER NOT NULL" + 864702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 865702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 866702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Cleans up when an audio genre is delete 867702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS audio_genres_cleanup DELETE ON audio_genres " + 868702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 869702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE FROM audio_genres_map WHERE genre_id = old._id;" + 870702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 871702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 872702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains audio playlist definitions 873702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS audio_playlists (" + 874702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 875702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_data TEXT," + // _data is path for file based playlists, or null 876702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "name TEXT NOT NULL," + 877702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_added INTEGER," + 878702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_modified INTEGER" + 879702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 880702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 881702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains mappings between audio playlists and audio files 882702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS audio_playlists_map (" + 883702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 884702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_id INTEGER NOT NULL," + 885702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "playlist_id INTEGER NOT NULL," + 886702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "play_order INTEGER NOT NULL" + 887702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 888702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 889702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Cleans up when an audio playlist is deleted 890702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS audio_playlists_cleanup DELETE ON audio_playlists " + 891702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 892702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE FROM audio_playlists_map WHERE playlist_id = old._id;" + 893702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT _DELETE_FILE(old._data);" + 894702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 895702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 896702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Cleans up album_art table entry when an album is deleted 897702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS albumart_cleanup1 DELETE ON albums " + 898702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 899702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE FROM album_art WHERE album_id = old.album_id;" + 900702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 901702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 902702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Cleans up album_art when an album is deleted 903702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS albumart_cleanup2 DELETE ON album_art " + 904702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 905702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT _DELETE_FILE(old._data);" + 906702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 907702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 908702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 909702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains meta data about video files 910702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS video (" + 911702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 912702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_data TEXT NOT NULL," + 913702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_display_name TEXT," + 914702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_size INTEGER," + 915702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "mime_type TEXT," + 916702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_added INTEGER," + 917702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_modified INTEGER," + 918702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "title TEXT," + 919702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "duration INTEGER," + 920702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "artist TEXT," + 921702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "album TEXT," + 922702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "resolution TEXT," + 923702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "description TEXT," + 924702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "isprivate INTEGER," + // for YouTube videos 925702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "tags TEXT," + // for YouTube videos 926702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "category TEXT," + // for YouTube videos 927702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "language TEXT," + // for YouTube videos 928702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "mini_thumb_data TEXT," + 929702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "latitude DOUBLE," + 930702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "longitude DOUBLE," + 931702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "datetaken INTEGER," + 932702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "mini_thumb_magic INTEGER" + 933702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 934702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 935702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS video_cleanup DELETE ON video " + 936702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 937702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT _DELETE_FILE(old._data);" + 938702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 939702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 940702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 941702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // At this point the database is at least at schema version 63 (it was 942702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // either created at version 63 by the code above, or was already at 943702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // version 63 or later) 944702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 945702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 64) { 946702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // create the index that updates the database to schema version 64 947702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE INDEX IF NOT EXISTS sort_index on images(datetaken ASC, _id ASC);"); 948702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 949702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 950acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen /* 951acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen * Android 1.0 shipped with database version 64 952acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen */ 953acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen 954702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 65) { 955702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // create the index that updates the database to schema version 65 956702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE INDEX IF NOT EXISTS titlekey_index on audio_meta(title_key);"); 957702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 958702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 959403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen // In version 66, originally we updateBucketNames(db, "images"), 960403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen // but we need to do it in version 89 and therefore save the update here. 961702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 962702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 67) { 963702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // create the indices that update the database to schema version 67 964702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE INDEX IF NOT EXISTS albumkey_index on albums(album_key);"); 965702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE INDEX IF NOT EXISTS artistkey_index on artists(artist_key);"); 966702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 967702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 968702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 68) { 969702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Create bucket_id and bucket_display_name columns for the video table. 970702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("ALTER TABLE video ADD COLUMN bucket_id TEXT;"); 971702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("ALTER TABLE video ADD COLUMN bucket_display_name TEXT"); 972403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen 973403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen // In version 68, originally we updateBucketNames(db, "video"), 974403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen // but we need to do it in version 89 and therefore save the update here. 975702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 976702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 977702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 69) { 978702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project updateDisplayName(db, "images"); 979702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 980702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 981702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 70) { 982702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Create bookmark column for the video table. 983702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("ALTER TABLE video ADD COLUMN bookmark INTEGER;"); 984702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 98595ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen 986702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 71) { 987702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // There is no change to the database schema, however a code change 988702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // fixed parsing of metadata for certain files bought from the 989702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // iTunes music store, so we want to rescan files that might need it. 990702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // We do this by clearing the modification date in the database for 991702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // those files, so that the media scanner will see them as updated 992702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // and rescan them. 993702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("UPDATE audio_meta SET date_modified=0 WHERE _id IN (" + 994702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT _id FROM audio where mime_type='audio/mp4' AND " + 995e31cfb1a2c21e7ac7a646d40afbb48f49fab6907Marco Nelissen "artist='" + MediaStore.UNKNOWN_STRING + "' AND " + 996e31cfb1a2c21e7ac7a646d40afbb48f49fab6907Marco Nelissen "album='" + MediaStore.UNKNOWN_STRING + "'" + 997702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 998702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 99995ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen 1000702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 72) { 1001702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Create is_podcast and bookmark columns for the audio table. 1002702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("ALTER TABLE audio_meta ADD COLUMN is_podcast INTEGER;"); 1003702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("UPDATE audio_meta SET is_podcast=1 WHERE _data LIKE '%/podcasts/%';"); 1004702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("UPDATE audio_meta SET is_music=0 WHERE is_podcast=1" + 1005702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " AND _data NOT LIKE '%/music/%';"); 1006702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("ALTER TABLE audio_meta ADD COLUMN bookmark INTEGER;"); 1007702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1008702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // New columns added to tables aren't visible in views on those tables 1009702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // without opening and closing the database (or using the 'vacuum' command, 1010702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // which we can't do here because all this code runs inside a transaction). 1011702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // To work around this, we drop and recreate the affected view and trigger. 1012702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project recreateAudioView(db); 1013702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 101495ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen 1015acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen /* 1016acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen * Android 1.5 shipped with database version 72 1017acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen */ 1018acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen 10198d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen if (fromVersion < 73) { 10208d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen // There is no change to the database schema, but we now do case insensitive 10218d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen // matching of folder names when determining whether something is music, a 10228d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen // ringtone, podcast, etc, so we might need to reclassify some files. 10238d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen db.execSQL("UPDATE audio_meta SET is_music=1 WHERE is_music=0 AND " + 10248d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen "_data LIKE '%/music/%';"); 10258d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen db.execSQL("UPDATE audio_meta SET is_ringtone=1 WHERE is_ringtone=0 AND " + 10268d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen "_data LIKE '%/ringtones/%';"); 10278d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen db.execSQL("UPDATE audio_meta SET is_notification=1 WHERE is_notification=0 AND " + 10288d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen "_data LIKE '%/notifications/%';"); 10298d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen db.execSQL("UPDATE audio_meta SET is_alarm=1 WHERE is_alarm=0 AND " + 10308d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen "_data LIKE '%/alarms/%';"); 10318d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen db.execSQL("UPDATE audio_meta SET is_podcast=1 WHERE is_podcast=0 AND " + 10328d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen "_data LIKE '%/podcasts/%';"); 10338d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen } 1034a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen 1035a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen if (fromVersion < 74) { 1036a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // This view is used instead of the audio view by the union below, to force 1037a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // sqlite to use the title_key index. This greatly reduces memory usage 1038a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // (no separate copy pass needed for sorting, which could cause errors on 1039a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // large datasets) and improves speed (by about 35% on a large dataset) 1040a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen db.execSQL("CREATE VIEW IF NOT EXISTS searchhelpertitle AS SELECT * FROM audio " + 1041a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "ORDER BY title_key;"); 1042a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen 1043a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen db.execSQL("CREATE VIEW IF NOT EXISTS search AS " + 1044a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "SELECT _id," + 1045a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "'artist' AS mime_type," + 1046a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist," + 1047a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS album," + 1048a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS title," + 1049a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist AS text1," + 1050a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS text2," + 1051a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "number_of_albums AS data1," + 1052a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "number_of_tracks AS data2," + 1053a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist_key AS match," + 1054a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "'content://media/external/audio/artists/'||_id AS suggest_intent_data," + 1055a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "1 AS grouporder " + 1056e31cfb1a2c21e7ac7a646d40afbb48f49fab6907Marco Nelissen "FROM artist_info WHERE (artist!='" + MediaStore.UNKNOWN_STRING + "') " + 1057a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "UNION ALL " + 1058a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "SELECT _id," + 1059a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "'album' AS mime_type," + 1060a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist," + 1061a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "album," + 1062a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS title," + 1063a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "album AS text1," + 1064a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist AS text2," + 1065a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS data1," + 1066a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS data2," + 1067a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist_key||' '||album_key AS match," + 1068a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "'content://media/external/audio/albums/'||_id AS suggest_intent_data," + 1069a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "2 AS grouporder " + 1070e31cfb1a2c21e7ac7a646d40afbb48f49fab6907Marco Nelissen "FROM album_info WHERE (album!='" + MediaStore.UNKNOWN_STRING + "') " + 1071a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "UNION ALL " + 1072a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "SELECT searchhelpertitle._id AS _id," + 1073a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "mime_type," + 1074a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist," + 1075a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "album," + 1076a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "title," + 1077a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "title AS text1," + 1078a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist AS text2," + 1079a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS data1," + 1080a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS data2," + 1081a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist_key||' '||album_key||' '||title_key AS match," + 1082a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "'content://media/external/audio/media/'||searchhelpertitle._id AS " + 1083a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "suggest_intent_data," + 1084a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "3 AS grouporder " + 1085a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "FROM searchhelpertitle WHERE (title != '') " 1086a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen ); 1087a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen } 108859948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen 108959948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen if (fromVersion < 75) { 109095ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen // Force a rescan of the audio entries so we can apply the new logic to 109159948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // distinguish same-named albums. 109259948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen db.execSQL("UPDATE audio_meta SET date_modified=0;"); 109359948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen db.execSQL("DELETE FROM albums"); 109459948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen } 109515d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen 109615d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen if (fromVersion < 76) { 109715d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen // We now ignore double quotes when building the key, so we have to remove all of them 109815d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen // from existing keys. 109915d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen db.execSQL("UPDATE audio_meta SET title_key=" + 110015d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen "REPLACE(title_key,x'081D08C29F081D',x'081D') " + 110115d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen "WHERE title_key LIKE '%'||x'081D08C29F081D'||'%';"); 110215d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen db.execSQL("UPDATE albums SET album_key=" + 110315d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen "REPLACE(album_key,x'081D08C29F081D',x'081D') " + 110415d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen "WHERE album_key LIKE '%'||x'081D08C29F081D'||'%';"); 110515d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen db.execSQL("UPDATE artists SET artist_key=" + 110615d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen "REPLACE(artist_key,x'081D08C29F081D',x'081D') " + 110715d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen "WHERE artist_key LIKE '%'||x'081D08C29F081D'||'%';"); 110815d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen } 1109b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1110acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen /* 1111acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen * Android 1.6 shipped with database version 76 1112acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen */ 1113acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen 1114b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (fromVersion < 77) { 1115b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // create video thumbnail table 1116b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen db.execSQL("CREATE TABLE IF NOT EXISTS videothumbnails (" + 1117b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "_id INTEGER PRIMARY KEY," + 1118b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "_data TEXT," + 1119b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "video_id INTEGER," + 1120b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "kind INTEGER," + 1121b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "width INTEGER," + 1122b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "height INTEGER" + 1123b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen ");"); 1124b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1125b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen db.execSQL("CREATE INDEX IF NOT EXISTS video_id_index on videothumbnails(video_id);"); 1126b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1127b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen db.execSQL("CREATE TRIGGER IF NOT EXISTS videothumbnails_cleanup DELETE ON videothumbnails " + 1128b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "BEGIN " + 1129b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "SELECT _DELETE_FILE(old._data);" + 1130b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "END"); 1131b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 11321769168ade7b67f8695a4e4f3c69625aca0811d5Ray Chen 1133acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen /* 1134acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen * Android 2.0 and 2.0.1 shipped with database version 77 1135acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen */ 1136acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen 11371769168ade7b67f8695a4e4f3c69625aca0811d5Ray Chen if (fromVersion < 78) { 1138044b029d9023f55e8e8861ed2f6e192f1b34f9bbRay Chen // Force a rescan of the video entries so we can update 11391769168ade7b67f8695a4e4f3c69625aca0811d5Ray Chen // latest changed DATE_TAKEN units (in milliseconds). 11401769168ade7b67f8695a4e4f3c69625aca0811d5Ray Chen db.execSQL("UPDATE video SET date_modified=0;"); 11411769168ade7b67f8695a4e4f3c69625aca0811d5Ray Chen } 1142268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen 1143acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen /* 1144acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen * Android 2.1 shipped with database version 78 1145acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen */ 1146acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen 1147268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen if (fromVersion < 79) { 1148268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen // move /sdcard/albumthumbs to 1149268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen // /sdcard/Android/data/com.android.providers.media/albumthumbs, 1150268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen // and update the database accordingly 1151268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen 11529be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood String oldthumbspath = mExternalStoragePaths[0] + "/albumthumbs"; 11539be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood String newthumbspath = mExternalStoragePaths[0] + "/" + ALBUM_THUMB_FOLDER; 1154268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen File thumbsfolder = new File(oldthumbspath); 1155268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen if (thumbsfolder.exists()) { 1156268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen // move folder to its new location 1157268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen File newthumbsfolder = new File(newthumbspath); 1158268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen newthumbsfolder.getParentFile().mkdirs(); 1159268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen if(thumbsfolder.renameTo(newthumbsfolder)) { 1160268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen // update the database 1161268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen db.execSQL("UPDATE album_art SET _data=REPLACE(_data, '" + 1162268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen oldthumbspath + "','" + newthumbspath + "');"); 1163268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen } 1164268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen } 1165268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen } 1166044b029d9023f55e8e8861ed2f6e192f1b34f9bbRay Chen 1167044b029d9023f55e8e8861ed2f6e192f1b34f9bbRay Chen if (fromVersion < 80) { 1168044b029d9023f55e8e8861ed2f6e192f1b34f9bbRay Chen // Force rescan of image entries to update DATE_TAKEN as UTC timestamp. 1169044b029d9023f55e8e8861ed2f6e192f1b34f9bbRay Chen db.execSQL("UPDATE images SET date_modified=0;"); 1170044b029d9023f55e8e8861ed2f6e192f1b34f9bbRay Chen } 11710ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen 1172166a4e3cc66a645cc5e11d2f06d059512def0aceMarco Nelissen if (fromVersion < 81 && !internal) { 11730ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // Delete entries starting with /mnt/sdcard. This is for the benefit 11740ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // of users running builds between 2.0.1 and 2.1 final only, since 11750ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // users updating from 2.0 or earlier will not have such entries. 11760ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen 11770ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // First we need to update the _data fields in the affected tables, since 11780ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // otherwise deleting the entries will also delete the underlying files 11790ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // (via a trigger), and we want to keep them. 11800ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE audio_playlists SET _data='////' WHERE _data LIKE '/mnt/sdcard/%';"); 11810ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE images SET _data='////' WHERE _data LIKE '/mnt/sdcard/%';"); 11820ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE video SET _data='////' WHERE _data LIKE '/mnt/sdcard/%';"); 11830ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE videothumbnails SET _data='////' WHERE _data LIKE '/mnt/sdcard/%';"); 11840ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE thumbnails SET _data='////' WHERE _data LIKE '/mnt/sdcard/%';"); 11850ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE album_art SET _data='////' WHERE _data LIKE '/mnt/sdcard/%';"); 1186216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen db.execSQL("UPDATE audio_meta SET _data='////' WHERE _data LIKE '/mnt/sdcard/%';"); 11870ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // Once the paths have been renamed, we can safely delete the entries 11880ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE FROM audio_playlists WHERE _data IS '////';"); 11890ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE FROM images WHERE _data IS '////';"); 11900ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE FROM video WHERE _data IS '////';"); 11910ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE FROM videothumbnails WHERE _data IS '////';"); 11920ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE FROM thumbnails WHERE _data IS '////';"); 11930ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE FROM audio_meta WHERE _data IS '////';"); 11940ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE FROM album_art WHERE _data IS '////';"); 11950ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen 11960ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // rename existing entries starting with /sdcard to /mnt/sdcard 11970ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE audio_meta" + 11980ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen " SET _data='/mnt/sdcard'||SUBSTR(_data,8) WHERE _data LIKE '/sdcard/%';"); 11990ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE audio_playlists" + 12000ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen " SET _data='/mnt/sdcard'||SUBSTR(_data,8) WHERE _data LIKE '/sdcard/%';"); 12010ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE images" + 12020ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen " SET _data='/mnt/sdcard'||SUBSTR(_data,8) WHERE _data LIKE '/sdcard/%';"); 12030ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE video" + 12040ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen " SET _data='/mnt/sdcard'||SUBSTR(_data,8) WHERE _data LIKE '/sdcard/%';"); 12050ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE videothumbnails" + 12060ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen " SET _data='/mnt/sdcard'||SUBSTR(_data,8) WHERE _data LIKE '/sdcard/%';"); 12070ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE thumbnails" + 12080ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen " SET _data='/mnt/sdcard'||SUBSTR(_data,8) WHERE _data LIKE '/sdcard/%';"); 12090ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE album_art" + 12100ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen " SET _data='/mnt/sdcard'||SUBSTR(_data,8) WHERE _data LIKE '/sdcard/%';"); 12110ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen 12120ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // Delete albums and artists, then clear the modification time on songs, which 12130ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // will cause the media scanner to rescan everything, rebuilding the artist and 12140ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // album tables along the way, while preserving playlists. 12150ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // We need this rescan because ICU also changed, and now generates different 12160ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // collation keys 12170ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE from albums"); 12180ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE from artists"); 12190ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE audio_meta SET date_modified=0;"); 12200ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen } 122184403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen 122284403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen if (fromVersion < 82) { 1223acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // recreate this view with the correct "group by" specifier 122484403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen db.execSQL("DROP VIEW IF EXISTS artist_info"); 122584403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen db.execSQL("CREATE VIEW IF NOT EXISTS artist_info AS " + 122684403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen "SELECT artist_id AS _id, artist, artist_key, " + 1227acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen "COUNT(DISTINCT album_key) AS number_of_albums, " + 122884403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen "COUNT(*) AS number_of_tracks FROM audio WHERE is_music=1 "+ 122984403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen "GROUP BY artist_key;"); 123084403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen } 1231216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen 1232acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen /* we skipped over version 83, and reverted versions 84, 85 and 86 */ 1233ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen 1234ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen if (fromVersion < 87) { 1235ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen // The fastscroll thumb needs an index on the strings being displayed, 1236ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen // otherwise the queries it does to determine the correct position 1237ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen // becomes really inefficient 1238022eb71bfe8ec65b8817eaa432a530194210ec23Marco Nelissen db.execSQL("CREATE INDEX IF NOT EXISTS title_idx on audio_meta(title);"); 1239022eb71bfe8ec65b8817eaa432a530194210ec23Marco Nelissen db.execSQL("CREATE INDEX IF NOT EXISTS artist_idx on artists(artist);"); 1240022eb71bfe8ec65b8817eaa432a530194210ec23Marco Nelissen db.execSQL("CREATE INDEX IF NOT EXISTS album_idx on albums(album);"); 1241ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen } 1242216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen 1243acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen if (fromVersion < 88) { 1244acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // Clean up a few more things from versions 84/85/86, and recreate 1245acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // the few things worth keeping from those changes. 1246acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS albums_update1;"); 1247acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS albums_update2;"); 1248acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS albums_update3;"); 1249acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS albums_update4;"); 1250acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS artist_update1;"); 1251acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS artist_update2;"); 1252acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS artist_update3;"); 1253acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS artist_update4;"); 125416dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood db.execSQL("DROP VIEW IF EXISTS album_artists;"); 1255acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("CREATE INDEX IF NOT EXISTS album_id_idx on audio_meta(album_id);"); 1256acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("CREATE INDEX IF NOT EXISTS artist_id_idx on audio_meta(artist_id);"); 1257acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // For a given artist_id, provides the album_id for albums on 1258acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // which the artist appears. 1259acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("CREATE VIEW IF NOT EXISTS artists_albums_map AS " + 1260acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen "SELECT DISTINCT artist_id, album_id FROM audio_meta;"); 1261acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen } 1262403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen 1263fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood // In version 89, originally we updateBucketNames(db, "images") and 1264fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood // updateBucketNames(db, "video"), but in version 101 we now updateBucketNames 1265fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood // for all files and therefore can save the update here. 1266b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 1267b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood if (fromVersion < 91) { 1268bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin // Never query by mini_thumb_magic_index 1269bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin db.execSQL("DROP INDEX IF EXISTS mini_thumb_magic_index"); 1270bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin 1271bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin // sort the items by taken date in each bucket 1272bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin db.execSQL("CREATE INDEX IF NOT EXISTS image_bucket_index ON images(bucket_id, datetaken)"); 1273bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin db.execSQL("CREATE INDEX IF NOT EXISTS video_bucket_index ON video(bucket_id, datetaken)"); 1274bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin } 1275bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin 1276a36cfaef630ef5df7bef80b25f6bd493d040c7e4Brian Muramatsu 1277d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen // Gingerbread ended up going to version 100, but didn't yet have the "files" 1278d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen // table, so we need to create that if we're at 100 or lower. This means 1279d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen // we won't be able to upgrade pre-release Honeycomb. 1280d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen if (fromVersion <= 100) { 1281afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // Remove various stages of work in progress for MTP support 1282afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TABLE IF EXISTS objects"); 1283afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TABLE IF EXISTS files"); 128416dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood db.execSQL("DROP TRIGGER IF EXISTS images_objects_cleanup;"); 128516dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood db.execSQL("DROP TRIGGER IF EXISTS audio_objects_cleanup;"); 128616dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood db.execSQL("DROP TRIGGER IF EXISTS video_objects_cleanup;"); 128716dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood db.execSQL("DROP TRIGGER IF EXISTS playlists_objects_cleanup;"); 1288afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TRIGGER IF EXISTS files_cleanup_images;"); 1289afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TRIGGER IF EXISTS files_cleanup_audio;"); 1290afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TRIGGER IF EXISTS files_cleanup_video;"); 1291afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TRIGGER IF EXISTS files_cleanup_playlists;"); 1292afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TRIGGER IF EXISTS media_cleanup;"); 1293afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1294afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // Create a new table to manage all files in our storage. 1295afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // This contains a union of all the columns from the old 1296afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // images, audio_meta, videos and audio_playlist tables. 1297afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE TABLE files (" + 129800a22306f6c99d1f1b4424f8f6a1cad8fb332d85Ray Chen "_id INTEGER PRIMARY KEY AUTOINCREMENT," + 1299afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "_data TEXT," + // this can be null for playlists 1300afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "_size INTEGER," + 1301afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "format INTEGER," + 1302afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "parent INTEGER," + 1303afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "date_added INTEGER," + 1304afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "date_modified INTEGER," + 1305afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "mime_type TEXT," + 1306afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "title TEXT," + 1307afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "description TEXT," + 1308afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "_display_name TEXT," + 1309afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1310afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // for images 1311afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "picasa_id TEXT," + 1312afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "orientation INTEGER," + 1313afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1314afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // for images and video 1315afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "latitude DOUBLE," + 1316afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "longitude DOUBLE," + 1317afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "datetaken INTEGER," + 1318afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "mini_thumb_magic INTEGER," + 1319afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "bucket_id TEXT," + 1320afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "bucket_display_name TEXT," + 1321afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "isprivate INTEGER," + 1322afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1323afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // for audio 1324afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "title_key TEXT," + 1325afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "artist_id INTEGER," + 1326afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "album_id INTEGER," + 1327afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "composer TEXT," + 1328afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "track INTEGER," + 1329afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "year INTEGER CHECK(year!=0)," + 1330afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "is_ringtone INTEGER," + 1331afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "is_music INTEGER," + 1332afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "is_alarm INTEGER," + 1333afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "is_notification INTEGER," + 1334afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "is_podcast INTEGER," + 1335d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen "album_artist TEXT," + 1336afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1337afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // for audio and video 1338afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "duration INTEGER," + 1339afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "bookmark INTEGER," + 1340afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1341afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // for video 1342afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "artist TEXT," + 1343afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "album TEXT," + 1344afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "resolution TEXT," + 1345afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "tags TEXT," + 1346afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "category TEXT," + 1347afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "language TEXT," + 1348afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "mini_thumb_data TEXT," + 1349afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1350afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // for playlists 1351afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "name TEXT," + 1352afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1353afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // media_type is used by the views to emulate the old 1354afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // images, audio_meta, videos and audio_playlist tables. 1355afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "media_type INTEGER," + 1356afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1357afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // Value of _id from the old media table. 1358afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // Used only for updating other tables during database upgrade. 1359afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "old_id INTEGER" + 1360afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood ");"); 1361d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen 1362afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE INDEX path_index ON files(_data);"); 1363afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE INDEX media_type_index ON files(media_type);"); 1364afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1365afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // Copy all data from our obsolete tables to the new files table 136692be385568284e6351ab49f5799eca0e35b9d98dMike Lockwood 136792be385568284e6351ab49f5799eca0e35b9d98dMike Lockwood // Copy audio records first, preserving the _id column. 136892be385568284e6351ab49f5799eca0e35b9d98dMike Lockwood // We do this to maintain compatibility for content Uris for ringtones. 136992be385568284e6351ab49f5799eca0e35b9d98dMike Lockwood // Unfortunately we cannot do this for images and videos as well. 137092be385568284e6351ab49f5799eca0e35b9d98dMike Lockwood // We choose to do this for the audio table because the fragility of Uris 137192be385568284e6351ab49f5799eca0e35b9d98dMike Lockwood // for ringtones are the most common problem we need to avoid. 137292be385568284e6351ab49f5799eca0e35b9d98dMike Lockwood db.execSQL("INSERT INTO files (_id," + AUDIO_COLUMNSv99 + ",old_id,media_type)" + 137392be385568284e6351ab49f5799eca0e35b9d98dMike Lockwood " SELECT _id," + AUDIO_COLUMNSv99 + ",_id," + FileColumns.MEDIA_TYPE_AUDIO + 137492be385568284e6351ab49f5799eca0e35b9d98dMike Lockwood " FROM audio_meta;"); 137592be385568284e6351ab49f5799eca0e35b9d98dMike Lockwood 1376bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang db.execSQL("INSERT INTO files (" + IMAGE_COLUMNSv407 + ",old_id,media_type) SELECT " 1377bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang + IMAGE_COLUMNSv407 + ",_id," + FileColumns.MEDIA_TYPE_IMAGE + " FROM images;"); 1378bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang db.execSQL("INSERT INTO files (" + VIDEO_COLUMNSv407 + ",old_id,media_type) SELECT " 1379bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang + VIDEO_COLUMNSv407 + ",_id," + FileColumns.MEDIA_TYPE_VIDEO + " FROM video;"); 138016dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood if (!internal) { 1381afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("INSERT INTO files (" + PLAYLIST_COLUMNS + ",old_id,media_type) SELECT " 1382afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + PLAYLIST_COLUMNS + ",_id," + FileColumns.MEDIA_TYPE_PLAYLIST 1383afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + " FROM audio_playlists;"); 1384afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 138516dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood 1386afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // Delete the old tables 1387afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TABLE IF EXISTS images"); 1388afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TABLE IF EXISTS audio_meta"); 1389afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TABLE IF EXISTS video"); 1390afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TABLE IF EXISTS audio_playlists"); 139116dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood 1392afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // Create views to replace our old tables 1393bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang db.execSQL("CREATE VIEW images AS SELECT _id," + IMAGE_COLUMNSv407 + 1394afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood " FROM files WHERE " + FileColumns.MEDIA_TYPE + "=" 1395afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + FileColumns.MEDIA_TYPE_IMAGE + ";"); 1396d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen db.execSQL("CREATE VIEW audio_meta AS SELECT _id," + AUDIO_COLUMNSv100 + 1397d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen " FROM files WHERE " + FileColumns.MEDIA_TYPE + "=" 1398d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen + FileColumns.MEDIA_TYPE_AUDIO + ";"); 1399bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang db.execSQL("CREATE VIEW video AS SELECT _id," + VIDEO_COLUMNSv407 + 1400afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood " FROM files WHERE " + FileColumns.MEDIA_TYPE + "=" 1401afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + FileColumns.MEDIA_TYPE_VIDEO + ";"); 1402afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (!internal) { 1403afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE VIEW audio_playlists AS SELECT _id," + PLAYLIST_COLUMNS + 1404afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood " FROM files WHERE " + FileColumns.MEDIA_TYPE + "=" 1405afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + FileColumns.MEDIA_TYPE_PLAYLIST + ";"); 140616dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood } 140736339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood 14089491c3bd011644f5fe69fd47f73d0e1245b33febMarco Nelissen // create temporary index to make the updates go faster 14099491c3bd011644f5fe69fd47f73d0e1245b33febMarco Nelissen db.execSQL("CREATE INDEX tmp ON files(old_id);"); 14109491c3bd011644f5fe69fd47f73d0e1245b33febMarco Nelissen 1411afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // update the image_id column in the thumbnails table. 1412afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("UPDATE thumbnails SET image_id = (SELECT _id FROM files " 1413afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + "WHERE files.old_id = thumbnails.image_id AND files.media_type = " 1414afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + FileColumns.MEDIA_TYPE_IMAGE + ");"); 141536339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood 1416afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (!internal) { 1417d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen // update audio_id in the audio_genres_map table, and 1418d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen // audio_playlists_map tables and playlist_id in the audio_playlists_map table 1419afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("UPDATE audio_genres_map SET audio_id = (SELECT _id FROM files " 1420afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + "WHERE files.old_id = audio_genres_map.audio_id AND files.media_type = " 1421afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + FileColumns.MEDIA_TYPE_AUDIO + ");"); 1422afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("UPDATE audio_playlists_map SET audio_id = (SELECT _id FROM files " 1423afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + "WHERE files.old_id = audio_playlists_map.audio_id " 1424afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + "AND files.media_type = " + FileColumns.MEDIA_TYPE_AUDIO + ");"); 1425d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen db.execSQL("UPDATE audio_playlists_map SET playlist_id = (SELECT _id FROM files " 1426d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen + "WHERE files.old_id = audio_playlists_map.playlist_id " 1427d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen + "AND files.media_type = " + FileColumns.MEDIA_TYPE_PLAYLIST + ");"); 1428afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 1429afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1430afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // update video_id in the videothumbnails table. 1431afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("UPDATE videothumbnails SET video_id = (SELECT _id FROM files " 1432afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + "WHERE files.old_id = videothumbnails.video_id AND files.media_type = " 1433afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + FileColumns.MEDIA_TYPE_VIDEO + ");"); 1434afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 14359491c3bd011644f5fe69fd47f73d0e1245b33febMarco Nelissen // we don't need this index anymore now 14369491c3bd011644f5fe69fd47f73d0e1245b33febMarco Nelissen db.execSQL("DROP INDEX tmp;"); 14379491c3bd011644f5fe69fd47f73d0e1245b33febMarco Nelissen 1438afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // update indices to work on the files table 1439afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP INDEX IF EXISTS title_idx"); 1440afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP INDEX IF EXISTS album_id_idx"); 1441afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP INDEX IF EXISTS image_bucket_index"); 1442afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP INDEX IF EXISTS video_bucket_index"); 1443afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP INDEX IF EXISTS sort_index"); 1444afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP INDEX IF EXISTS titlekey_index"); 1445afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP INDEX IF EXISTS artist_id_idx"); 1446afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE INDEX title_idx ON files(title);"); 1447afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE INDEX album_id_idx ON files(album_id);"); 1448afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE INDEX bucket_index ON files(bucket_id, datetaken);"); 1449afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE INDEX sort_index ON files(datetaken ASC, _id ASC);"); 1450afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE INDEX titlekey_index ON files(title_key);"); 1451afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE INDEX artist_id_idx ON files(artist_id);"); 1452afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1453afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // Recreate triggers for our obsolete tables on the new files table 1454afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TRIGGER IF EXISTS images_cleanup"); 1455afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TRIGGER IF EXISTS audio_meta_cleanup"); 1456afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TRIGGER IF EXISTS video_cleanup"); 1457afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TRIGGER IF EXISTS audio_playlists_cleanup"); 1458afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TRIGGER IF EXISTS audio_delete"); 145936339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood 1460afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE TRIGGER IF NOT EXISTS images_cleanup DELETE ON files " + 1461afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "WHEN old.media_type = " + FileColumns.MEDIA_TYPE_IMAGE + " " + 146236339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood "BEGIN " + 1463afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "DELETE FROM thumbnails WHERE image_id = old._id;" + 1464afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "SELECT _DELETE_FILE(old._data);" + 146536339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood "END"); 146636339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood 1467afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE TRIGGER IF NOT EXISTS video_cleanup DELETE ON files " + 146849dea76284f7693ba452c05cfd59c1d9c9584343Ray Chen "WHEN old.media_type = " + FileColumns.MEDIA_TYPE_VIDEO + " " + 146936339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood "BEGIN " + 1470afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "SELECT _DELETE_FILE(old._data);" + 147136339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood "END"); 147236339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood 1473afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (!internal) { 1474afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE TRIGGER IF NOT EXISTS audio_meta_cleanup DELETE ON files " + 1475afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "WHEN old.media_type = " + FileColumns.MEDIA_TYPE_AUDIO + " " + 1476afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "BEGIN " + 1477afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "DELETE FROM audio_genres_map WHERE audio_id = old._id;" + 1478afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "DELETE FROM audio_playlists_map WHERE audio_id = old._id;" + 1479afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "END"); 1480afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1481afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE TRIGGER IF NOT EXISTS audio_playlists_cleanup DELETE ON files " + 1482afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "WHEN old.media_type = " + FileColumns.MEDIA_TYPE_PLAYLIST + " " + 1483afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "BEGIN " + 1484afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "DELETE FROM audio_playlists_map WHERE playlist_id = old._id;" + 1485afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "SELECT _DELETE_FILE(old._data);" + 1486afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "END"); 1487afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1488afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE TRIGGER IF NOT EXISTS audio_delete INSTEAD OF DELETE ON audio " + 148936339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood "BEGIN " + 1490afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "DELETE from files where _id=old._id;" + 1491afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "DELETE from audio_playlists_map where audio_id=old._id;" + 1492afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "DELETE from audio_genres_map where audio_id=old._id;" + 149336339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood "END"); 149436339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood } 149536339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood } 149636339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood 1497fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood if (fromVersion < 300) { 1498fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood // we now compute bucket and display names for all files to avoid problems with files 1499fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood // that the media scanner might not recognize as images or videos 1500fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood updateBucketNames(db, "files"); 1501fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood } 1502fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood 1503db8357b2b2888ce3778278e9cd9e698347ca6105Owen Lin if (fromVersion < 301) { 1504db8357b2b2888ce3778278e9cd9e698347ca6105Owen Lin db.execSQL("DROP INDEX IF EXISTS bucket_index"); 1505db8357b2b2888ce3778278e9cd9e698347ca6105Owen Lin db.execSQL("CREATE INDEX bucket_index on files(bucket_id, media_type, datetaken, _id)"); 1506db8357b2b2888ce3778278e9cd9e698347ca6105Owen Lin db.execSQL("CREATE INDEX bucket_name on files(bucket_id, media_type, bucket_display_name)"); 1507db8357b2b2888ce3778278e9cd9e698347ca6105Owen Lin } 1508db8357b2b2888ce3778278e9cd9e698347ca6105Owen Lin 150920405fab4cf752dbdec6f1020bfc70a2bf87590eMike Lockwood if (fromVersion < 302) { 151020405fab4cf752dbdec6f1020bfc70a2bf87590eMike Lockwood db.execSQL("CREATE INDEX parent_index ON files(parent);"); 151120405fab4cf752dbdec6f1020bfc70a2bf87590eMike Lockwood db.execSQL("CREATE INDEX format_index ON files(format);"); 151220405fab4cf752dbdec6f1020bfc70a2bf87590eMike Lockwood } 151320405fab4cf752dbdec6f1020bfc70a2bf87590eMike Lockwood 15142658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen if (fromVersion < 303) { 15152658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen // the album disambiguator hash changed, so rescan songs and force 15162658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen // albums to be updated. Artists are unaffected. 15172658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen db.execSQL("DELETE from albums"); 15182658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen db.execSQL("UPDATE files SET date_modified=0 WHERE " + FileColumns.MEDIA_TYPE + "=" 15192658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen + FileColumns.MEDIA_TYPE_AUDIO + ";"); 15202658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen } 15212658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen 15224b5963f15c1563c613ec505ca7962f93aec44321Mike Lockwood if (fromVersion < 304 && !internal) { 152351d6c5d233f78de2db9b3f63514b20b1ce768dd5Mike Lockwood // notifies host when files are deleted 152451d6c5d233f78de2db9b3f63514b20b1ce768dd5Mike Lockwood db.execSQL("CREATE TRIGGER IF NOT EXISTS files_cleanup DELETE ON files " + 152551d6c5d233f78de2db9b3f63514b20b1ce768dd5Mike Lockwood "BEGIN " + 152651d6c5d233f78de2db9b3f63514b20b1ce768dd5Mike Lockwood "SELECT _OBJECT_REMOVED(old._id);" + 152751d6c5d233f78de2db9b3f63514b20b1ce768dd5Mike Lockwood "END"); 152851d6c5d233f78de2db9b3f63514b20b1ce768dd5Mike Lockwood 152951d6c5d233f78de2db9b3f63514b20b1ce768dd5Mike Lockwood } 153051d6c5d233f78de2db9b3f63514b20b1ce768dd5Mike Lockwood 15314b5963f15c1563c613ec505ca7962f93aec44321Mike Lockwood if (fromVersion < 305 && internal) { 15324b5963f15c1563c613ec505ca7962f93aec44321Mike Lockwood // version 304 erroneously added this trigger to the internal database 15334b5963f15c1563c613ec505ca7962f93aec44321Mike Lockwood db.execSQL("DROP TRIGGER IF EXISTS files_cleanup"); 15344b5963f15c1563c613ec505ca7962f93aec44321Mike Lockwood } 15354b5963f15c1563c613ec505ca7962f93aec44321Mike Lockwood 1536fda522dc66b94057f9c6676cb8ba10bc3b13daeaMarco Nelissen if (fromVersion < 306 && !internal) { 1537efe0bcdf5ed215a5cb76c8a48aad1333056636f4Marco Nelissen // The genre list was expanded and genre string parsing was tweaked, so 1538efe0bcdf5ed215a5cb76c8a48aad1333056636f4Marco Nelissen // rebuild the genre list 1539efe0bcdf5ed215a5cb76c8a48aad1333056636f4Marco Nelissen db.execSQL("UPDATE files SET date_modified=0 WHERE " + FileColumns.MEDIA_TYPE + "=" 1540efe0bcdf5ed215a5cb76c8a48aad1333056636f4Marco Nelissen + FileColumns.MEDIA_TYPE_AUDIO + ";"); 1541efe0bcdf5ed215a5cb76c8a48aad1333056636f4Marco Nelissen db.execSQL("DELETE FROM audio_genres_map"); 1542efe0bcdf5ed215a5cb76c8a48aad1333056636f4Marco Nelissen db.execSQL("DELETE FROM audio_genres"); 1543efe0bcdf5ed215a5cb76c8a48aad1333056636f4Marco Nelissen } 1544efe0bcdf5ed215a5cb76c8a48aad1333056636f4Marco Nelissen 154565587f9c204abb2d179527dfdca009f4780e9743Ray Chen if (fromVersion < 307 && !internal) { 154665587f9c204abb2d179527dfdca009f4780e9743Ray Chen // Force rescan of image entries to update DATE_TAKEN by either GPSTimeStamp or 154765587f9c204abb2d179527dfdca009f4780e9743Ray Chen // EXIF local time. 154865587f9c204abb2d179527dfdca009f4780e9743Ray Chen db.execSQL("UPDATE files SET date_modified=0 WHERE " + FileColumns.MEDIA_TYPE + "=" 154965587f9c204abb2d179527dfdca009f4780e9743Ray Chen + FileColumns.MEDIA_TYPE_IMAGE + ";"); 155065587f9c204abb2d179527dfdca009f4780e9743Ray Chen } 155165587f9c204abb2d179527dfdca009f4780e9743Ray Chen 15524f63f7c1e6f602a77abd43b189f296b9eb36635bMike Lockwood // Database version 401 did not add storage_id to the internal database. 15534f63f7c1e6f602a77abd43b189f296b9eb36635bMike Lockwood // We need it there too, so add it in version 402 15544f63f7c1e6f602a77abd43b189f296b9eb36635bMike Lockwood if (fromVersion < 401 || (fromVersion == 401 && internal)) { 15559be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood // Add column for MTP storage ID 15569be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood db.execSQL("ALTER TABLE files ADD COLUMN storage_id INTEGER;"); 15579be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood // Anything in the database before this upgrade step will be in the primary storage 15589be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood db.execSQL("UPDATE files SET storage_id=" + MtpStorage.getStorageId(0) + ";"); 15599be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood } 15609be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood 156178b2885edc406273d688536b0eadfea006b20662Marco Nelissen if (fromVersion < 403 && !internal) { 156278b2885edc406273d688536b0eadfea006b20662Marco Nelissen db.execSQL("CREATE VIEW audio_genres_map_noid AS " + 156378b2885edc406273d688536b0eadfea006b20662Marco Nelissen "SELECT audio_id,genre_id from audio_genres_map;"); 156478b2885edc406273d688536b0eadfea006b20662Marco Nelissen } 156578b2885edc406273d688536b0eadfea006b20662Marco Nelissen 15669289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen if (fromVersion < 404) { 15679289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen // There was a bug that could cause distinct same-named albums to be 15689289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen // combined again. Delete albums and force a rescan. 15699289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen db.execSQL("DELETE from albums"); 15709289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen db.execSQL("UPDATE files SET date_modified=0 WHERE " + FileColumns.MEDIA_TYPE + "=" 15719289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen + FileColumns.MEDIA_TYPE_AUDIO + ";"); 15729289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen } 15739289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen 1574957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang if (fromVersion < 405) { 1575957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang // Add is_drm column. 1576957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang db.execSQL("ALTER TABLE files ADD COLUMN is_drm INTEGER;"); 1577957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang 1578957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang db.execSQL("DROP VIEW IF EXISTS audio_meta"); 1579957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang db.execSQL("CREATE VIEW audio_meta AS SELECT _id," + AUDIO_COLUMNSv405 + 1580957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang " FROM files WHERE " + FileColumns.MEDIA_TYPE + "=" 1581957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang + FileColumns.MEDIA_TYPE_AUDIO + ";"); 1582957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang 1583957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang recreateAudioView(db); 1584957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang } 1585957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang 1586b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood if (fromVersion < 407) { 15877ee82723c70fc02b168cfa9b6ff7d5fdd0c16d53Gloria Wang // Rescan files in the media database because a new column has been added 1588b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood // in table files in version 405 and to recover from problems populating 1589b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood // the genre tables 15907ee82723c70fc02b168cfa9b6ff7d5fdd0c16d53Gloria Wang db.execSQL("UPDATE files SET date_modified=0;"); 15917ee82723c70fc02b168cfa9b6ff7d5fdd0c16d53Gloria Wang } 15927ee82723c70fc02b168cfa9b6ff7d5fdd0c16d53Gloria Wang 1593bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang if (fromVersion < 408) { 1594bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang // Add the width/height columns for images and video 1595bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang db.execSQL("ALTER TABLE files ADD COLUMN width INTEGER;"); 1596bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang db.execSQL("ALTER TABLE files ADD COLUMN height INTEGER;"); 1597bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang 1598bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang // Rescan files to fill the columns 1599bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang db.execSQL("UPDATE files SET date_modified=0;"); 1600bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang 1601bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang // Update images and video views to contain the width/height columns 1602bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang db.execSQL("DROP VIEW IF EXISTS images"); 1603bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang db.execSQL("DROP VIEW IF EXISTS video"); 1604bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang db.execSQL("CREATE VIEW images AS SELECT _id," + IMAGE_COLUMNS + 1605bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang " FROM files WHERE " + FileColumns.MEDIA_TYPE + "=" 1606bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang + FileColumns.MEDIA_TYPE_IMAGE + ";"); 1607bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang db.execSQL("CREATE VIEW video AS SELECT _id," + VIDEO_COLUMNS + 1608bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang " FROM files WHERE " + FileColumns.MEDIA_TYPE + "=" 1609bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang + FileColumns.MEDIA_TYPE_VIDEO + ";"); 1610bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang } 1611bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang 16125809eb2b5fd77bd7d14548669c70e4a672e43df6Marco Nelissen if (fromVersion < 409 && !internal) { 16135809eb2b5fd77bd7d14548669c70e4a672e43df6Marco Nelissen // A bug that prevented numeric genres from being parsed was fixed, so 16145809eb2b5fd77bd7d14548669c70e4a672e43df6Marco Nelissen // rebuild the genre list 16155809eb2b5fd77bd7d14548669c70e4a672e43df6Marco Nelissen db.execSQL("UPDATE files SET date_modified=0 WHERE " + FileColumns.MEDIA_TYPE + "=" 16165809eb2b5fd77bd7d14548669c70e4a672e43df6Marco Nelissen + FileColumns.MEDIA_TYPE_AUDIO + ";"); 16175809eb2b5fd77bd7d14548669c70e4a672e43df6Marco Nelissen db.execSQL("DELETE FROM audio_genres_map"); 16185809eb2b5fd77bd7d14548669c70e4a672e43df6Marco Nelissen db.execSQL("DELETE FROM audio_genres"); 16195809eb2b5fd77bd7d14548669c70e4a672e43df6Marco Nelissen } 16205809eb2b5fd77bd7d14548669c70e4a672e43df6Marco Nelissen 1621166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen if (fromVersion < 500) { 1622166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen // we're now deleting the file in mediaprovider code, rather than via a trigger 1623166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen db.execSQL("DROP TRIGGER IF EXISTS videothumbnails_cleanup;"); 1624166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen } 1625a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen if (fromVersion < 501) { 1626a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen // we're now deleting the file in mediaprovider code, rather than via a trigger 1627a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen // the images_cleanup trigger would delete the image file and the entry 1628a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen // in the thumbnail table, which in turn would trigger thumbnails_cleanup 1629a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen // to delete the thumbnail image 1630a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen db.execSQL("DROP TRIGGER IF EXISTS images_cleanup;"); 1631a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen db.execSQL("DROP TRIGGER IF EXISTS thumbnails_cleanup;"); 1632a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen } 16335afff430a4ebb751dadeb0112a1fe2052c6f5c05Marco Nelissen if (fromVersion < 502) { 16345afff430a4ebb751dadeb0112a1fe2052c6f5c05Marco Nelissen // we're now deleting the file in mediaprovider code, rather than via a trigger 16355afff430a4ebb751dadeb0112a1fe2052c6f5c05Marco Nelissen db.execSQL("DROP TRIGGER IF EXISTS video_cleanup;"); 16365afff430a4ebb751dadeb0112a1fe2052c6f5c05Marco Nelissen } 16375118dba282c95fda77e03e63b6dd11505c474ee5Marco Nelissen if (fromVersion < 503) { 16385118dba282c95fda77e03e63b6dd11505c474ee5Marco Nelissen // genre and playlist cleanup now done in mediaprovider code, instead of in a trigger 16395118dba282c95fda77e03e63b6dd11505c474ee5Marco Nelissen db.execSQL("DROP TRIGGER IF EXISTS audio_delete"); 16405118dba282c95fda77e03e63b6dd11505c474ee5Marco Nelissen db.execSQL("DROP TRIGGER IF EXISTS audio_meta_cleanup"); 16415118dba282c95fda77e03e63b6dd11505c474ee5Marco Nelissen } 164290c7da0610b7c3f4d9f4f3b2767e0bae5f3ab258Marco Nelissen if (fromVersion < 504) { 164390c7da0610b7c3f4d9f4f3b2767e0bae5f3ab258Marco Nelissen // add an index to help with case-insensitive matching of paths 164490c7da0610b7c3f4d9f4f3b2767e0bae5f3ab258Marco Nelissen db.execSQL( 164590c7da0610b7c3f4d9f4f3b2767e0bae5f3ab258Marco Nelissen "CREATE INDEX IF NOT EXISTS path_index_lower ON files(_data COLLATE NOCASE);"); 164690c7da0610b7c3f4d9f4f3b2767e0bae5f3ab258Marco Nelissen } 1647acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen sanityCheck(db, fromVersion); 16481d4a8ec9e1e62427088dc40f08872a10c863535eMarco Nelissen } 16491d4a8ec9e1e62427088dc40f08872a10c863535eMarco Nelissen 16501d4a8ec9e1e62427088dc40f08872a10c863535eMarco Nelissen /** 1651216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen * Perform a simple sanity check on the database. Currently this tests 1652216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen * whether all the _data entries in audio_meta are unique 1653216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen */ 1654216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen private static void sanityCheck(SQLiteDatabase db, int fromVersion) { 1655216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen Cursor c1 = db.query("audio_meta", new String[] {"count(*)"}, 1656216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen null, null, null, null, null); 1657216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen Cursor c2 = db.query("audio_meta", new String[] {"count(distinct _data)"}, 1658216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen null, null, null, null, null); 1659216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen c1.moveToFirst(); 1660216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen c2.moveToFirst(); 1661216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen int num1 = c1.getInt(0); 1662216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen int num2 = c2.getInt(0); 1663216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen c1.close(); 1664216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen c2.close(); 1665216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen if (num1 != num2) { 1666216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen Log.e(TAG, "audio_meta._data column is not unique while upgrading" + 1667216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen " from schema " +fromVersion + " : " + num1 +"/" + num2); 1668216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen // Delete all audio_meta rows so they will be rebuilt by the media scanner 1669216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen db.execSQL("DELETE FROM audio_meta;"); 1670216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen } 1671702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1672702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1673702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static void recreateAudioView(SQLiteDatabase db) { 1674702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Provides a unified audio/artist/album info view. 1675702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Note that views are read-only, so we define a trigger to allow deletes. 1676702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP VIEW IF EXISTS audio"); 1677702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE VIEW IF NOT EXISTS audio as SELECT * FROM audio_meta " + 1678702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "LEFT OUTER JOIN artists ON audio_meta.artist_id=artists.artist_id " + 1679702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "LEFT OUTER JOIN albums ON audio_meta.album_id=albums.album_id;"); 1680702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 168195ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen 1682702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 1683702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Iterate through the rows of a table in a database, ensuring that the bucket_id and 1684702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * bucket_display_name columns are correct. 1685702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param db 1686702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param tableName 1687702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 1688702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static void updateBucketNames(SQLiteDatabase db, String tableName) { 1689702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Rebuild the bucket_display_name column using the natural case rather than lower case. 1690702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.beginTransaction(); 1691702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 1692702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String[] columns = {BaseColumns._ID, MediaColumns.DATA}; 1693702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Cursor cursor = db.query(tableName, columns, null, null, null, null, null); 1694702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 1695702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final int idColumnIndex = cursor.getColumnIndex(BaseColumns._ID); 1696702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final int dataColumnIndex = cursor.getColumnIndex(MediaColumns.DATA); 16979491c3bd011644f5fe69fd47f73d0e1245b33febMarco Nelissen String [] rowId = new String[1]; 1698702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project while (cursor.moveToNext()) { 1699702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String data = cursor.getString(dataColumnIndex); 17009491c3bd011644f5fe69fd47f73d0e1245b33febMarco Nelissen rowId[0] = String.valueOf(cursor.getInt(idColumnIndex)); 1701d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen if (data != null) { 1702d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen ContentValues values = new ContentValues(); 1703d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen computeBucketValues(data, values); 17049491c3bd011644f5fe69fd47f73d0e1245b33febMarco Nelissen db.update(tableName, values, "_id=?", rowId); 1705d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen } else { 1706d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen Log.w(TAG, "null data at id " + rowId); 1707d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen } 1708702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1709702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 1710702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project cursor.close(); 1711702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1712702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.setTransactionSuccessful(); 1713702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 1714702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.endTransaction(); 1715702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1716702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1717702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1718702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 1719702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Iterate through the rows of a table in a database, ensuring that the 1720702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * display name column has a value. 1721702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param db 1722702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param tableName 1723702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 1724702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static void updateDisplayName(SQLiteDatabase db, String tableName) { 1725702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Fill in default values for null displayName values 1726702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.beginTransaction(); 1727702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 1728702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String[] columns = {BaseColumns._ID, MediaColumns.DATA, MediaColumns.DISPLAY_NAME}; 1729702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Cursor cursor = db.query(tableName, columns, null, null, null, null, null); 1730702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 1731702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final int idColumnIndex = cursor.getColumnIndex(BaseColumns._ID); 1732702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final int dataColumnIndex = cursor.getColumnIndex(MediaColumns.DATA); 1733702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final int displayNameIndex = cursor.getColumnIndex(MediaColumns.DISPLAY_NAME); 1734702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(); 1735702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project while (cursor.moveToNext()) { 1736702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String displayName = cursor.getString(displayNameIndex); 1737702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (displayName == null) { 1738702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String data = cursor.getString(dataColumnIndex); 1739702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.clear(); 1740702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project computeDisplayName(data, values); 1741702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int rowId = cursor.getInt(idColumnIndex); 1742702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.update(tableName, values, "_id=" + rowId, null); 1743702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1744702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1745702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 1746702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project cursor.close(); 1747702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1748702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.setTransactionSuccessful(); 1749702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 1750702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.endTransaction(); 1751702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1752702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1753702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 1754702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param data The input path 1755702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param values the content values, where the bucked id name and bucket display name are updated. 1756702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 1757702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 1758702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1759702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static void computeBucketValues(String data, ContentValues values) { 1760702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File parentFile = new File(data).getParentFile(); 1761702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (parentFile == null) { 1762702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project parentFile = new File("/"); 1763702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1764702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1765702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Lowercase the path for hashing. This avoids duplicate buckets if the 1766702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // filepath case is changed externally. 1767702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Keep the original case for display. 1768702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String path = parentFile.toString().toLowerCase(); 1769702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String name = parentFile.getName(); 1770702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1771702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Note: the BUCKET_ID and BUCKET_DISPLAY_NAME attributes are spelled the 1772702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // same for both images and video. However, for backwards-compatibility reasons 1773702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // there is no common base class. We use the ImageColumns version here 1774d0d809c65db7d4936266c8f6a18511046c84fd15Mike Lockwood values.put(ImageColumns.BUCKET_ID, path.hashCode()); 1775702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(ImageColumns.BUCKET_DISPLAY_NAME, name); 1776702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1777702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1778702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 1779702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param data The input path 1780702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param values the content values, where the display name is updated. 1781702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 1782702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 1783702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static void computeDisplayName(String data, ContentValues values) { 1784702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String s = (data == null ? "" : data.toString()); 1785702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int idx = s.lastIndexOf('/'); 1786702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (idx >= 0) { 1787702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project s = s.substring(idx + 1); 1788702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1789702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put("_display_name", s); 1790702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1791702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1792b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen /** 1793498b62c2912302a23532c73a028a7684c5df33caRay Chen * Copy taken time from date_modified if we lost the original value (e.g. after factory reset) 1794498b62c2912302a23532c73a028a7684c5df33caRay Chen * This works for both video and image tables. 1795b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen * 1796b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen * @param values the content values, where taken time is updated. 1797b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen */ 1798b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen private static void computeTakenTime(ContentValues values) { 1799b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen if (! values.containsKey(Images.Media.DATE_TAKEN)) { 1800b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen // This only happens when MediaScanner finds an image file that doesn't have any useful 1801b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen // reference to get this value. (e.g. GPSTimeStamp) 1802498b62c2912302a23532c73a028a7684c5df33caRay Chen Long lastModified = values.getAsLong(MediaColumns.DATE_MODIFIED); 1803b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen if (lastModified != null) { 1804b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen values.put(Images.Media.DATE_TAKEN, lastModified * 1000); 1805b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen } 1806b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen } 1807b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen } 1808b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen 1809b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen /** 1810b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen * This method blocks until thumbnail is ready. 1811b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen * 1812b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen * @param thumbUri 1813b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen * @return 1814b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen */ 1815b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private boolean waitForThumbnailReady(Uri origUri) { 1816b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen Cursor c = this.query(origUri, new String[] { ImageColumns._ID, ImageColumns.DATA, 1817b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen ImageColumns.MINI_THUMB_MAGIC}, null, null, null); 1818b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (c == null) return false; 1819b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1820b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen boolean result = false; 1821b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1822b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (c.moveToFirst()) { 1823e263c2a4b880ef8a5314bb4379c74bf5f9292bd0Ray Chen long id = c.getLong(0); 1824b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen String path = c.getString(1); 1825b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen long magic = c.getLong(2); 1826b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 18279299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen MediaThumbRequest req = requestMediaThumbnail(path, origUri, 18289299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen MediaThumbRequest.PRIORITY_HIGH, magic); 18299299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen if (req == null) { 18309299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen return false; 18319299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen } 18329299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen synchronized (req) { 18339299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen try { 18349299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen while (req.mState == MediaThumbRequest.State.WAIT) { 18359299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen req.wait(); 183620434e032e498b716f87cce2f23dd646819218bfRay Chen } 18379299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen } catch (InterruptedException e) { 18389299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen Log.w(TAG, e); 18399299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen } 18409299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen if (req.mState == MediaThumbRequest.State.DONE) { 18419299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen result = true; 1842b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1843b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1844b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1845b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen c.close(); 1846b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1847b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return result; 1848b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1849b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1850e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen private boolean matchThumbRequest(MediaThumbRequest req, int pid, long id, long gid, 1851e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen boolean isVideo) { 1852e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen boolean cancelAllOrigId = (id == -1); 1853e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen boolean cancelAllGroupId = (gid == -1); 1854e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen return (req.mCallingPid == pid) && 1855e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen (cancelAllGroupId || req.mGroupId == gid) && 1856e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen (cancelAllOrigId || req.mOrigId == id) && 1857e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen (req.mIsVideo == isVideo); 1858e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen } 1859e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen 1860b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private boolean queryThumbnail(SQLiteQueryBuilder qb, Uri uri, String table, 1861b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen String column, boolean hasThumbnailId) { 1862b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen qb.setTables(table); 1863b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (hasThumbnailId) { 1864b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // For uri dispatched to this method, the 4th path segment is always 1865b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // the thumbnail id. 1866b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen qb.appendWhere("_id = " + uri.getPathSegments().get(3)); 1867b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // client already knows which thumbnail it wants, bypass it. 1868b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return true; 1869b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1870b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen String origId = uri.getQueryParameter("orig_id"); 1871b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // We can't query ready_flag unless we know original id 1872b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (origId == null) { 1873b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // this could be thumbnail query for other purpose, bypass it. 1874b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return true; 1875b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1876b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1877b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen boolean needBlocking = "1".equals(uri.getQueryParameter("blocking")); 187820434e032e498b716f87cce2f23dd646819218bfRay Chen boolean cancelRequest = "1".equals(uri.getQueryParameter("cancel")); 1879e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen Uri origUri = uri.buildUpon().encodedPath( 1880e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen uri.getPath().replaceFirst("thumbnails", "media")) 1881e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen .appendPath(origId).build(); 1882b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1883b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (needBlocking && !waitForThumbnailReady(origUri)) { 188420434e032e498b716f87cce2f23dd646819218bfRay Chen Log.w(TAG, "original media doesn't exist or it's canceled."); 1885b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return false; 188620434e032e498b716f87cce2f23dd646819218bfRay Chen } else if (cancelRequest) { 1887e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen String groupId = uri.getQueryParameter("group_id"); 1888e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen boolean isVideo = "video".equals(uri.getPathSegments().get(1)); 188920434e032e498b716f87cce2f23dd646819218bfRay Chen int pid = Binder.getCallingPid(); 189020434e032e498b716f87cce2f23dd646819218bfRay Chen long id = -1; 1891e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen long gid = -1; 1892e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen 189320434e032e498b716f87cce2f23dd646819218bfRay Chen try { 189420434e032e498b716f87cce2f23dd646819218bfRay Chen id = Long.parseLong(origId); 1895e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen gid = Long.parseLong(groupId); 189620434e032e498b716f87cce2f23dd646819218bfRay Chen } catch (NumberFormatException ex) { 189720434e032e498b716f87cce2f23dd646819218bfRay Chen // invalid cancel request 189820434e032e498b716f87cce2f23dd646819218bfRay Chen return false; 189920434e032e498b716f87cce2f23dd646819218bfRay Chen } 1900e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen 190120434e032e498b716f87cce2f23dd646819218bfRay Chen synchronized (mMediaThumbQueue) { 1902e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen if (mCurrentThumbRequest != null && 1903e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen matchThumbRequest(mCurrentThumbRequest, pid, id, gid, isVideo)) { 190420434e032e498b716f87cce2f23dd646819218bfRay Chen synchronized (mCurrentThumbRequest) { 190520434e032e498b716f87cce2f23dd646819218bfRay Chen mCurrentThumbRequest.mState = MediaThumbRequest.State.CANCEL; 190620434e032e498b716f87cce2f23dd646819218bfRay Chen mCurrentThumbRequest.notifyAll(); 190720434e032e498b716f87cce2f23dd646819218bfRay Chen } 190820434e032e498b716f87cce2f23dd646819218bfRay Chen } 190920434e032e498b716f87cce2f23dd646819218bfRay Chen for (MediaThumbRequest mtq : mMediaThumbQueue) { 1910e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen if (matchThumbRequest(mtq, pid, id, gid, isVideo)) { 191120434e032e498b716f87cce2f23dd646819218bfRay Chen synchronized (mtq) { 191220434e032e498b716f87cce2f23dd646819218bfRay Chen mtq.mState = MediaThumbRequest.State.CANCEL; 191320434e032e498b716f87cce2f23dd646819218bfRay Chen mtq.notifyAll(); 191420434e032e498b716f87cce2f23dd646819218bfRay Chen } 191520434e032e498b716f87cce2f23dd646819218bfRay Chen 191620434e032e498b716f87cce2f23dd646819218bfRay Chen mMediaThumbQueue.remove(mtq); 191720434e032e498b716f87cce2f23dd646819218bfRay Chen } 191820434e032e498b716f87cce2f23dd646819218bfRay Chen } 191920434e032e498b716f87cce2f23dd646819218bfRay Chen } 1920b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1921b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1922b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (origId != null) { 1923b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen qb.appendWhere(column + " = " + origId); 1924b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1925b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return true; 1926b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1927b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen @SuppressWarnings("fallthrough") 1928702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 1929702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public Cursor query(Uri uri, String[] projectionIn, String selection, 1930702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String[] selectionArgs, String sort) { 1931702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int table = URI_MATCHER.match(uri); 1932baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen List<String> prependArgs = new ArrayList<String>(); 1933702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 193401a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen // Log.v(TAG, "query: uri="+uri+", selection="+selection); 1935702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // handle MEDIA_SCANNER before calling getDatabaseForUri() 1936702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (table == MEDIA_SCANNER) { 1937702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (mMediaScannerVolume == null) { 1938702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return null; 1939702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 1940702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // create a cursor to return volume currently being scanned by the media scanner 19410027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen MatrixCursor c = new MatrixCursor(new String[] {MediaStore.MEDIA_SCANNER_VOLUME}); 19420027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen c.addRow(new String[] {mMediaScannerVolume}); 19430027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen return c; 1944702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1945702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1946702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 19470027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen // Used temporarily (until we have unique media IDs) to get an identifier 19480027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen // for the current sd card, so that the music app doesn't have to use the 19490027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen // non-public getFatVolumeId method 19500027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen if (table == FS_ID) { 19510027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen MatrixCursor c = new MatrixCursor(new String[] {"fsid"}); 19520027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen c.addRow(new Integer[] {mVolumeId}); 19530027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen return c; 19540027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen } 19550027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen 1956704a8b507b7aa61a09457075ed6f80c95914d731Marco Nelissen if (table == VERSION) { 1957704a8b507b7aa61a09457075ed6f80c95914d731Marco Nelissen MatrixCursor c = new MatrixCursor(new String[] {"version"}); 195890c7da0610b7c3f4d9f4f3b2767e0bae5f3ab258Marco Nelissen c.addRow(new Integer[] {getDatabaseVersion(getContext())}); 1959704a8b507b7aa61a09457075ed6f80c95914d731Marco Nelissen return c; 1960704a8b507b7aa61a09457075ed6f80c95914d731Marco Nelissen } 1961704a8b507b7aa61a09457075ed6f80c95914d731Marco Nelissen 1962702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String groupBy = null; 196310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen DatabaseHelper helper = getDatabaseForUri(uri); 196410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen if (helper == null) { 1965702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return null; 1966702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 196710af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumQueries++; 196810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen SQLiteDatabase db = helper.getReadableDatabase(); 19695fde670987a55d69442566dcbdb7830d5f1587c6Chih-Chung Chang if (db == null) return null; 1970702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 19714574e03055af60fada50481f2b34e19a687d5866Marco Nelissen String limit = uri.getQueryParameter("limit"); 1972c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen String filter = uri.getQueryParameter("filter"); 1973c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen String [] keywords = null; 1974c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen if (filter != null) { 1975c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen filter = Uri.decode(filter).trim(); 1976c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen if (!TextUtils.isEmpty(filter)) { 1977c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen String [] searchWords = filter.split(" "); 1978c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen keywords = new String[searchWords.length]; 1979c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen Collator col = Collator.getInstance(); 1980c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen col.setStrength(Collator.PRIMARY); 1981c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen for (int i = 0; i < searchWords.length; i++) { 1982c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen String key = MediaStore.Audio.keyFor(searchWords[i]); 1983c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen key = key.replace("\\", "\\\\"); 1984c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen key = key.replace("%", "\\%"); 1985c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen key = key.replace("_", "\\_"); 1986c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen keywords[i] = key; 1987c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen } 1988c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen } 1989c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen } 1990db8357b2b2888ce3778278e9cd9e698347ca6105Owen Lin if (uri.getQueryParameter("distinct") != null) { 1991db8357b2b2888ce3778278e9cd9e698347ca6105Owen Lin qb.setDistinct(true); 1992db8357b2b2888ce3778278e9cd9e698347ca6105Owen Lin } 1993c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen 1994b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen boolean hasThumbnailId = false; 1995702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1996702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (table) { 1997702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA: 1998702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("images"); 1999702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (uri.getQueryParameter("distinct") != null) 2000702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setDistinct(true); 2001702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2002702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // set the project map so that data dir is prepended to _data. 2003702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project //qb.setProjectionMap(mImagesProjectionMap, true); 2004702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2005702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2006702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA_ID: 2007702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("images"); 2008702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (uri.getQueryParameter("distinct") != null) 2009702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setDistinct(true); 2010702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2011702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // set the project map so that data dir is prepended to _data. 2012702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project //qb.setProjectionMap(mImagesProjectionMap, true); 2013baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen qb.appendWhere("_id=?"); 2014baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(3)); 2015702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2016702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2017702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_THUMBNAILS_ID: 2018b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen hasThumbnailId = true; 2019b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case IMAGES_THUMBNAILS: 2020b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (!queryThumbnail(qb, uri, "thumbnails", "image_id", hasThumbnailId)) { 2021b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return null; 2022b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 2023702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2024702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2025702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA: 2026d9672f4d28ab9038333a0037fe30e386ac0ce610Marco Nelissen if (projectionIn != null && projectionIn.length == 1 && selectionArgs == null 2027ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen && (selection == null || selection.equalsIgnoreCase("is_music=1") 2028ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen || selection.equalsIgnoreCase("is_podcast=1") ) 2029c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen && projectionIn[0].equalsIgnoreCase("count(*)") 2030c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen && keywords != null) { 2031ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen //Log.i("@@@@", "taking fast path for counting songs"); 2032ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.setTables("audio_meta"); 2033ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen } else { 2034ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.setTables("audio"); 2035c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen for (int i = 0; keywords != null && i < keywords.length; i++) { 2036c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen if (i > 0) { 2037c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen qb.appendWhere(" AND "); 2038c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen } 2039c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen qb.appendWhere(MediaStore.Audio.Media.ARTIST_KEY + 2040c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen "||" + MediaStore.Audio.Media.ALBUM_KEY + 2041baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen "||" + MediaStore.Audio.Media.TITLE_KEY + " LIKE ? ESCAPE '\\'"); 2042baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add("%" + keywords[i] + "%"); 2043c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen } 2044ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen } 2045702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2046702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2047702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID: 2048702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio"); 2049baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen qb.appendWhere("_id=?"); 2050baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(3)); 2051702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2052702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2053702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES: 2054702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_genres"); 2055702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id IN (SELECT genre_id FROM " + 2056baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen "audio_genres_map WHERE audio_id=?)"); 2057baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(3)); 2058702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2059702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2060702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES_ID: 2061702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_genres"); 2062baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen qb.appendWhere("_id=?"); 2063baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(5)); 2064702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2065702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2066702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS: 2067702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_playlists"); 2068702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id IN (SELECT playlist_id FROM " + 2069baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen "audio_playlists_map WHERE audio_id=?)"); 2070baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(3)); 2071702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2072702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2073702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS_ID: 2074702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_playlists"); 2075baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen qb.appendWhere("_id=?"); 2076baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(5)); 2077702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2078702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2079702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES: 2080702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_genres"); 2081702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2082702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2083702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID: 2084702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_genres"); 2085baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen qb.appendWhere("_id=?"); 2086baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(3)); 2087702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2088702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2089bfbc30ff3b9e3a96b08c525d0971d8d8543ab000Marco Nelissen case AUDIO_GENRES_ALL_MEMBERS: 2090702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID_MEMBERS: 209178b2885edc406273d688536b0eadfea006b20662Marco Nelissen { 209278b2885edc406273d688536b0eadfea006b20662Marco Nelissen // if simpleQuery is true, we can do a simpler query on just audio_genres_map 209378b2885edc406273d688536b0eadfea006b20662Marco Nelissen // we can do this if we have no keywords and our projection includes just columns 209478b2885edc406273d688536b0eadfea006b20662Marco Nelissen // from audio_genres_map 209578b2885edc406273d688536b0eadfea006b20662Marco Nelissen boolean simpleQuery = (keywords == null && projectionIn != null 209678b2885edc406273d688536b0eadfea006b20662Marco Nelissen && (selection == null || selection.equalsIgnoreCase("genre_id=?"))); 209778b2885edc406273d688536b0eadfea006b20662Marco Nelissen if (projectionIn != null) { 209878b2885edc406273d688536b0eadfea006b20662Marco Nelissen for (int i = 0; i < projectionIn.length; i++) { 209978b2885edc406273d688536b0eadfea006b20662Marco Nelissen String p = projectionIn[i]; 210078b2885edc406273d688536b0eadfea006b20662Marco Nelissen if (p.equals("_id")) { 210178b2885edc406273d688536b0eadfea006b20662Marco Nelissen // note, this is different from playlist below, because 210278b2885edc406273d688536b0eadfea006b20662Marco Nelissen // "_id" used to (wrongly) be the audio id in this query, not 210378b2885edc406273d688536b0eadfea006b20662Marco Nelissen // the row id of the entry in the map, and we preserve this 210478b2885edc406273d688536b0eadfea006b20662Marco Nelissen // behavior for backwards compatibility 210578b2885edc406273d688536b0eadfea006b20662Marco Nelissen simpleQuery = false; 210678b2885edc406273d688536b0eadfea006b20662Marco Nelissen } 210778b2885edc406273d688536b0eadfea006b20662Marco Nelissen if (simpleQuery && !(p.equals("audio_id") || 210878b2885edc406273d688536b0eadfea006b20662Marco Nelissen p.equals("genre_id"))) { 210978b2885edc406273d688536b0eadfea006b20662Marco Nelissen simpleQuery = false; 211078b2885edc406273d688536b0eadfea006b20662Marco Nelissen } 211178b2885edc406273d688536b0eadfea006b20662Marco Nelissen } 211278b2885edc406273d688536b0eadfea006b20662Marco Nelissen } 211378b2885edc406273d688536b0eadfea006b20662Marco Nelissen if (simpleQuery) { 211478b2885edc406273d688536b0eadfea006b20662Marco Nelissen qb.setTables("audio_genres_map_noid"); 2115bfbc30ff3b9e3a96b08c525d0971d8d8543ab000Marco Nelissen if (table == AUDIO_GENRES_ID_MEMBERS) { 2116baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen qb.appendWhere("genre_id=?"); 2117baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(3)); 2118bfbc30ff3b9e3a96b08c525d0971d8d8543ab000Marco Nelissen } 211978b2885edc406273d688536b0eadfea006b20662Marco Nelissen } else { 212078b2885edc406273d688536b0eadfea006b20662Marco Nelissen qb.setTables("audio_genres_map_noid, audio"); 2121bfbc30ff3b9e3a96b08c525d0971d8d8543ab000Marco Nelissen qb.appendWhere("audio._id = audio_id"); 2122bfbc30ff3b9e3a96b08c525d0971d8d8543ab000Marco Nelissen if (table == AUDIO_GENRES_ID_MEMBERS) { 2123baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen qb.appendWhere(" AND genre_id=?"); 2124baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(3)); 2125bfbc30ff3b9e3a96b08c525d0971d8d8543ab000Marco Nelissen } 212678b2885edc406273d688536b0eadfea006b20662Marco Nelissen for (int i = 0; keywords != null && i < keywords.length; i++) { 212778b2885edc406273d688536b0eadfea006b20662Marco Nelissen qb.appendWhere(" AND "); 212878b2885edc406273d688536b0eadfea006b20662Marco Nelissen qb.appendWhere(MediaStore.Audio.Media.ARTIST_KEY + 212978b2885edc406273d688536b0eadfea006b20662Marco Nelissen "||" + MediaStore.Audio.Media.ALBUM_KEY + 213078b2885edc406273d688536b0eadfea006b20662Marco Nelissen "||" + MediaStore.Audio.Media.TITLE_KEY + 2131baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen " LIKE ? ESCAPE '\\'"); 2132baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add("%" + keywords[i] + "%"); 213378b2885edc406273d688536b0eadfea006b20662Marco Nelissen } 213478b2885edc406273d688536b0eadfea006b20662Marco Nelissen } 213578b2885edc406273d688536b0eadfea006b20662Marco Nelissen } 2136702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2137702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2138702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS: 2139702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_playlists"); 2140702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2141702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2142702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID: 2143702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_playlists"); 2144baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen qb.appendWhere("_id=?"); 2145baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(3)); 2146702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2147702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2148b5f293f3888b304e0b78c0039d7326c20e778b9fMarco Nelissen case AUDIO_PLAYLISTS_ID_MEMBERS_ID: 2149702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS: 2150e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood // if simpleQuery is true, we can do a simpler query on just audio_playlists_map 2151e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood // we can do this if we have no keywords and our projection includes just columns 2152e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood // from audio_playlists_map 21534382d5ecf11d3c70eed9ba7b09970ef254774b6dMike Lockwood boolean simpleQuery = (keywords == null && projectionIn != null 21544382d5ecf11d3c70eed9ba7b09970ef254774b6dMike Lockwood && (selection == null || selection.equalsIgnoreCase("playlist_id=?"))); 215597e61d89d90a1bd6989a254660aa80553662e002Marco Nelissen if (projectionIn != null) { 215697e61d89d90a1bd6989a254660aa80553662e002Marco Nelissen for (int i = 0; i < projectionIn.length; i++) { 2157e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood String p = projectionIn[i]; 2158e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood if (simpleQuery && !(p.equals("audio_id") || 2159e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood p.equals("playlist_id") || p.equals("play_order"))) { 2160e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood simpleQuery = false; 2161e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood } 2162e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood if (p.equals("_id")) { 216397e61d89d90a1bd6989a254660aa80553662e002Marco Nelissen projectionIn[i] = "audio_playlists_map._id AS _id"; 216497e61d89d90a1bd6989a254660aa80553662e002Marco Nelissen } 2165702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2166702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2167e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood if (simpleQuery) { 2168e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood qb.setTables("audio_playlists_map"); 2169baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen qb.appendWhere("playlist_id=?"); 2170baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(3)); 2171e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood } else { 2172e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood qb.setTables("audio_playlists_map, audio"); 2173baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen qb.appendWhere("audio._id = audio_id AND playlist_id=?"); 2174baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(3)); 2175e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood for (int i = 0; keywords != null && i < keywords.length; i++) { 2176e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood qb.appendWhere(" AND "); 2177e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood qb.appendWhere(MediaStore.Audio.Media.ARTIST_KEY + 2178e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood "||" + MediaStore.Audio.Media.ALBUM_KEY + 2179e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood "||" + MediaStore.Audio.Media.TITLE_KEY + 2180baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen " LIKE ? ESCAPE '\\'"); 2181baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add("%" + keywords[i] + "%"); 2182e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood } 2183c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen } 2184b5f293f3888b304e0b78c0039d7326c20e778b9fMarco Nelissen if (table == AUDIO_PLAYLISTS_ID_MEMBERS_ID) { 2185baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen qb.appendWhere(" AND audio_playlists_map._id=?"); 2186baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(5)); 2187b5f293f3888b304e0b78c0039d7326c20e778b9fMarco Nelissen } 2188702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2189702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2190702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA: 2191702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("video"); 2192702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2193702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA_ID: 2194702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("video"); 2195baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen qb.appendWhere("_id=?"); 2196baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(3)); 2197702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2198702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2199b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case VIDEO_THUMBNAILS_ID: 2200b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen hasThumbnailId = true; 2201b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case VIDEO_THUMBNAILS: 2202b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (!queryThumbnail(qb, uri, "videothumbnails", "video_id", hasThumbnailId)) { 2203b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return null; 2204b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 2205b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen break; 2206b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 2207702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ARTISTS: 2208d9672f4d28ab9038333a0037fe30e386ac0ce610Marco Nelissen if (projectionIn != null && projectionIn.length == 1 && selectionArgs == null 2209ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen && (selection == null || selection.length() == 0) 2210c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen && projectionIn[0].equalsIgnoreCase("count(*)") 2211c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen && keywords != null) { 2212ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen //Log.i("@@@@", "taking fast path for counting artists"); 2213ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.setTables("audio_meta"); 2214ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen projectionIn[0] = "count(distinct artist_id)"; 2215ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.appendWhere("is_music=1"); 2216ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen } else { 2217ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.setTables("artist_info"); 2218c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen for (int i = 0; keywords != null && i < keywords.length; i++) { 2219c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen if (i > 0) { 2220c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen qb.appendWhere(" AND "); 2221c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen } 2222c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen qb.appendWhere(MediaStore.Audio.Media.ARTIST_KEY + 2223baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen " LIKE ? ESCAPE '\\'"); 2224baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add("%" + keywords[i] + "%"); 2225c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen } 2226ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen } 2227702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2228702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2229702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ARTISTS_ID: 2230702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("artist_info"); 2231baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen qb.appendWhere("_id=?"); 2232baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(3)); 2233702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2234702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2235702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ARTISTS_ID_ALBUMS: 2236702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String aid = uri.getPathSegments().get(3); 2237acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen qb.setTables("audio LEFT OUTER JOIN album_art ON" + 2238acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen " audio.album_id=album_art.album_id"); 2239acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen qb.appendWhere("is_music=1 AND audio.album_id IN (SELECT album_id FROM " + 2240baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen "artists_albums_map WHERE artist_id=?)"); 2241baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(aid); 2242c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen for (int i = 0; keywords != null && i < keywords.length; i++) { 2243c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen qb.appendWhere(" AND "); 2244c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen qb.appendWhere(MediaStore.Audio.Media.ARTIST_KEY + 2245c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen "||" + MediaStore.Audio.Media.ALBUM_KEY + 2246baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen " LIKE ? ESCAPE '\\'"); 2247baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add("%" + keywords[i] + "%"); 2248c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen } 2249acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen groupBy = "audio.album_id"; 2250702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Albums.NUMBER_OF_SONGS_FOR_ARTIST, 2251acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen "count(CASE WHEN artist_id==" + aid + " THEN 'foo' ELSE NULL END) AS " + 2252702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.Audio.Albums.NUMBER_OF_SONGS_FOR_ARTIST); 2253702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setProjectionMap(sArtistAlbumsMap); 2254702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2255702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2256702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ALBUMS: 2257d9672f4d28ab9038333a0037fe30e386ac0ce610Marco Nelissen if (projectionIn != null && projectionIn.length == 1 && selectionArgs == null 2258ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen && (selection == null || selection.length() == 0) 2259c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen && projectionIn[0].equalsIgnoreCase("count(*)") 2260c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen && keywords != null) { 2261ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen //Log.i("@@@@", "taking fast path for counting albums"); 2262ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.setTables("audio_meta"); 2263ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen projectionIn[0] = "count(distinct album_id)"; 2264ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.appendWhere("is_music=1"); 2265ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen } else { 2266ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.setTables("album_info"); 2267c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen for (int i = 0; keywords != null && i < keywords.length; i++) { 2268c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen if (i > 0) { 2269c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen qb.appendWhere(" AND "); 2270c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen } 2271c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen qb.appendWhere(MediaStore.Audio.Media.ARTIST_KEY + 2272c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen "||" + MediaStore.Audio.Media.ALBUM_KEY + 2273baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen " LIKE ? ESCAPE '\\'"); 2274baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add("%" + keywords[i] + "%"); 2275c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen } 2276ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen } 2277702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2278702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2279702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ALBUMS_ID: 2280702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("album_info"); 2281baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen qb.appendWhere("_id=?"); 2282baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(3)); 2283702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2284702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2285702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ALBUMART_ID: 2286702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("album_art"); 2287baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen qb.appendWhere("album_id=?"); 2288baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(3)); 2289702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2290702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2291a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen case AUDIO_SEARCH_LEGACY: 2292a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen Log.w(TAG, "Legacy media search Uri used. Please update your code."); 2293a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // fall through 2294a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen case AUDIO_SEARCH_FANCY: 2295a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen case AUDIO_SEARCH_BASIC: 2296baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen return doAudioSearch(db, qb, uri, projectionIn, selection, 2297baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen combine(prependArgs, selectionArgs), sort, table, limit); 2298702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 229916dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood case FILES_ID: 2300e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood case MTP_OBJECTS_ID: 2301baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen qb.appendWhere("_id=?"); 2302baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(2)); 2303b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood // fall through 230416dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood case FILES: 2305e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood case MTP_OBJECTS: 230616dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood qb.setTables("files"); 2307b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood break; 2308b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 2309e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood case MTP_OBJECT_REFERENCES: 2310e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood int handle = Integer.parseInt(uri.getPathSegments().get(2)); 231110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen return getObjectReferences(helper, db, handle); 2312e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood 2313702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project default: 2314702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalStateException("Unknown URL: " + uri.toString()); 2315702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2316702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2317baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen // Log.v(TAG, "query = "+ qb.buildQuery(projectionIn, selection, 2318baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen // combine(prependArgs, selectionArgs), groupBy, null, sort, limit)); 2319702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Cursor c = qb.query(db, projectionIn, selection, 2320baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen combine(prependArgs, selectionArgs), groupBy, null, sort, limit); 2321b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 2322702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (c != null) { 2323702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project c.setNotificationUri(getContext().getContentResolver(), uri); 2324702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2325b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 2326702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return c; 2327702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2328702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2329baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen private String[] combine(List<String> prepend, String[] userArgs) { 2330baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen int presize = prepend.size(); 2331baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen if (presize == 0) { 2332baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen return userArgs; 2333baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen } 2334baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen 2335baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen int usersize = (userArgs != null) ? userArgs.length : 0; 2336baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen String [] combined = new String[presize + usersize]; 2337baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen for (int i = 0; i < presize; i++) { 2338baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen combined[i] = prepend.get(i); 2339baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen } 2340baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen for (int i = 0; i < usersize; i++) { 2341baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen combined[presize + i] = userArgs[i]; 2342baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen } 2343baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen return combined; 2344baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen } 2345baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen 2346702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private Cursor doAudioSearch(SQLiteDatabase db, SQLiteQueryBuilder qb, 2347702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Uri uri, String[] projectionIn, String selection, 23484574e03055af60fada50481f2b34e19a687d5866Marco Nelissen String[] selectionArgs, String sort, int mode, 23494574e03055af60fada50481f2b34e19a687d5866Marco Nelissen String limit) { 2350702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 235118c787fb045725bf10bf630ac0917a48def9ace5Marco Nelissen String mSearchString = uri.getPath().endsWith("/") ? "" : uri.getLastPathSegment(); 2352702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mSearchString = mSearchString.replaceAll(" ", " ").trim().toLowerCase(); 2353702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2354702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String [] searchWords = mSearchString.length() > 0 ? 2355702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mSearchString.split(" ") : new String[0]; 2356a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen String [] wildcardWords = new String[searchWords.length]; 2357702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Collator col = Collator.getInstance(); 2358702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project col.setStrength(Collator.PRIMARY); 2359702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int len = searchWords.length; 2360702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project for (int i = 0; i < len; i++) { 2361702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Because we match on individual words here, we need to remove words 2362702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // like 'a' and 'the' that aren't part of the keys. 23633001ef332046c69cbb70289be29442fcc0ad5f6fMarco Nelissen String key = MediaStore.Audio.keyFor(searchWords[i]); 23643001ef332046c69cbb70289be29442fcc0ad5f6fMarco Nelissen key = key.replace("\\", "\\\\"); 23653001ef332046c69cbb70289be29442fcc0ad5f6fMarco Nelissen key = key.replace("%", "\\%"); 23663001ef332046c69cbb70289be29442fcc0ad5f6fMarco Nelissen key = key.replace("_", "\\_"); 2367a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen wildcardWords[i] = 2368702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project (searchWords[i].equals("a") || searchWords[i].equals("an") || 23693001ef332046c69cbb70289be29442fcc0ad5f6fMarco Nelissen searchWords[i].equals("the")) ? "%" : "%" + key + "%"; 2370702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2371702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2372a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen String where = ""; 2373a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen for (int i = 0; i < searchWords.length; i++) { 2374a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen if (i == 0) { 23753001ef332046c69cbb70289be29442fcc0ad5f6fMarco Nelissen where = "match LIKE ? ESCAPE '\\'"; 2376a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen } else { 23773001ef332046c69cbb70289be29442fcc0ad5f6fMarco Nelissen where += " AND match LIKE ? ESCAPE '\\'"; 2378702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2379702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2380702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2381a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen qb.setTables("search"); 2382a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen String [] cols; 2383a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen if (mode == AUDIO_SEARCH_FANCY) { 2384a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen cols = mSearchColsFancy; 2385a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen } else if (mode == AUDIO_SEARCH_BASIC) { 2386a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen cols = mSearchColsBasic; 2387a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen } else { 2388a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen cols = mSearchColsLegacy; 2389702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 23904574e03055af60fada50481f2b34e19a687d5866Marco Nelissen return qb.query(db, cols, where, wildcardWords, null, null, null, limit); 2391702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2392702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2393702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 2394702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public String getType(Uri url) 2395702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project { 2396702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (URI_MATCHER.match(url)) { 2397702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA_ID: 2398702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID: 2399702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS_ID: 2400702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA_ID: 2401c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood case FILES_ID: 240226f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen Cursor c = null; 240326f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen try { 240426f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen c = query(url, MIME_TYPE_PROJECTION, null, null, null); 240526f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen if (c != null && c.getCount() == 1) { 240626f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen c.moveToFirst(); 240726f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen String mimeType = c.getString(1); 240826f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen c.deactivate(); 240926f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen return mimeType; 241026f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen } 241126f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen } finally { 241226f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen if (c != null) { 241326f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen c.close(); 241426f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen } 2415702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2416702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2417702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2418702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA: 2419702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_THUMBNAILS: 2420702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Images.Media.CONTENT_TYPE; 2421804f5fe841d4a96f9335ea60d60853352f726227Marco Nelissen case AUDIO_ALBUMART_ID: 2422702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_THUMBNAILS_ID: 2423702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return "image/jpeg"; 2424702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2425702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA: 2426702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID_MEMBERS: 2427702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS: 2428702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Audio.Media.CONTENT_TYPE; 2429702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2430702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES: 2431702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES: 2432702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Audio.Genres.CONTENT_TYPE; 2433702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID: 2434702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES_ID: 2435702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Audio.Genres.ENTRY_CONTENT_TYPE; 2436702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS: 2437702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS: 2438702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Audio.Playlists.CONTENT_TYPE; 2439702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID: 2440702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS_ID: 2441702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Audio.Playlists.ENTRY_CONTENT_TYPE; 2442702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2443702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA: 2444702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Video.Media.CONTENT_TYPE; 2445702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2446804f5fe841d4a96f9335ea60d60853352f726227Marco Nelissen throw new IllegalStateException("Unknown URL : " + url); 2447702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2448702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2449702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 2450702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Ensures there is a file in the _data column of values, if one isn't 2451702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * present a new file is created. 2452702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 2453702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param initialValues the values passed to insert by the caller 2454702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @return the new values 2455702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 2456702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private ContentValues ensureFile(boolean internal, ContentValues initialValues, 2457702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String preferredExtension, String directoryName) { 2458702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values; 2459801ba04ac37ee06dccb8bf4081b29a162795e3a6Mike Lockwood String file = initialValues.getAsString(MediaStore.MediaColumns.DATA); 2460702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (TextUtils.isEmpty(file)) { 2461702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project file = generateFileName(internal, preferredExtension, directoryName); 2462702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values = new ContentValues(initialValues); 2463801ba04ac37ee06dccb8bf4081b29a162795e3a6Mike Lockwood values.put(MediaStore.MediaColumns.DATA, file); 2464702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 2465702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values = initialValues; 2466702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2467702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2468702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!ensureFileExists(file)) { 2469702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalStateException("Unable to create new file: " + file); 2470702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2471702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return values; 2472702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2473702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2474d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood private void sendObjectAdded(long objectHandle) { 247534be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood synchronized (mMtpServiceConnection) { 247634be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood if (mMtpService != null) { 247734be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood try { 247834be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood mMtpService.sendObjectAdded((int)objectHandle); 247934be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood } catch (RemoteException e) { 248034be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood Log.e(TAG, "RemoteException in sendObjectAdded", e); 248134be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood mMtpService = null; 248234be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood } 2483d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 2484d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 2485d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 2486d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 2487d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood private void sendObjectRemoved(long objectHandle) { 248834be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood synchronized (mMtpServiceConnection) { 248934be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood if (mMtpService != null) { 249034be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood try { 249134be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood mMtpService.sendObjectRemoved((int)objectHandle); 249234be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood } catch (RemoteException e) { 249334be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood Log.e(TAG, "RemoteException in sendObjectRemoved", e); 249434be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood mMtpService = null; 249534be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood } 2496d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 2497d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 2498d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 2499d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 2500702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 2501702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public int bulkInsert(Uri uri, ContentValues values[]) { 2502702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int match = URI_MATCHER.match(uri); 2503702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (match == VOLUMES) { 2504702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return super.bulkInsert(uri, values); 2505702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 250610af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen DatabaseHelper helper = getDatabaseForUri(uri); 250710af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen if (helper == null) { 2508702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException( 2509702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Unknown URI: " + uri); 2510702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 251110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen SQLiteDatabase db = helper.getWritableDatabase(); 25125fde670987a55d69442566dcbdb7830d5f1587c6Chih-Chung Chang if (db == null) { 25135fde670987a55d69442566dcbdb7830d5f1587c6Chih-Chung Chang throw new IllegalStateException("Couldn't open database for " + uri); 25145fde670987a55d69442566dcbdb7830d5f1587c6Chih-Chung Chang } 2515ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen 2516ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen if (match == AUDIO_PLAYLISTS_ID || match == AUDIO_PLAYLISTS_ID_MEMBERS) { 2517ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen return playlistBulkInsert(db, uri, values); 2518e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } else if (match == MTP_OBJECT_REFERENCES) { 2519e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood int handle = Integer.parseInt(uri.getPathSegments().get(2)); 252010af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen return setObjectReferences(helper, db, handle, values); 2521ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen } 2522ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen 2523702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.beginTransaction(); 2524702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int numInserted = 0; 2525702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 2526702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int len = values.length; 2527702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project for (int i = 0; i < len; i++) { 2528801ba04ac37ee06dccb8bf4081b29a162795e3a6Mike Lockwood if (values[i] != null) { 2529801ba04ac37ee06dccb8bf4081b29a162795e3a6Mike Lockwood insertInternal(uri, match, values[i]); 2530801ba04ac37ee06dccb8bf4081b29a162795e3a6Mike Lockwood } 2531702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2532702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project numInserted = len; 2533702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.setTransactionSuccessful(); 2534702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 2535702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.endTransaction(); 2536702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2537702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 2538702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return numInserted; 2539702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2540702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2541702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 2542801ba04ac37ee06dccb8bf4081b29a162795e3a6Mike Lockwood public Uri insert(Uri uri, ContentValues initialValues) { 25435d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood int match = URI_MATCHER.match(uri); 25445d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood Uri newUri = insertInternal(uri, match, initialValues); 25455d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood // do not signal notification for MTP objects. 25465d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood // we will signal instead after file transfer is successful. 2547e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood if (newUri != null && match != MTP_OBJECTS) { 2548702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 2549702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2550702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return newUri; 2551702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2552702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2553ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen private int playlistBulkInsert(SQLiteDatabase db, Uri uri, ContentValues values[]) { 2554ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen DatabaseUtils.InsertHelper helper = 2555ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen new DatabaseUtils.InsertHelper(db, "audio_playlists_map"); 25568b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen int audioidcolidx = helper.getColumnIndex(MediaStore.Audio.Playlists.Members.AUDIO_ID); 25578b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen int playlistididx = helper.getColumnIndex(Audio.Playlists.Members.PLAYLIST_ID); 25588b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen int playorderidx = helper.getColumnIndex(MediaStore.Audio.Playlists.Members.PLAY_ORDER); 25598b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen long playlistId = Long.parseLong(uri.getPathSegments().get(3)); 2560ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen 2561ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen db.beginTransaction(); 2562ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen int numInserted = 0; 2563ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen try { 2564ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen int len = values.length; 2565ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen for (int i = 0; i < len; i++) { 25668b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen helper.prepareForInsert(); 25678b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen // getting the raw Object and converting it long ourselves saves 25688b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen // an allocation (the alternative is ContentValues.getAsLong, which 25698b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen // returns a Long object) 25708b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen long audioid = ((Number) values[i].get( 25718b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen MediaStore.Audio.Playlists.Members.AUDIO_ID)).longValue(); 25728b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen helper.bind(audioidcolidx, audioid); 25738b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen helper.bind(playlistididx, playlistId); 25748b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen // convert to int ourselves to save an allocation. 25758b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen int playorder = ((Number) values[i].get( 25768b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen MediaStore.Audio.Playlists.Members.PLAY_ORDER)).intValue(); 25778b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen helper.bind(playorderidx, playorder); 25788b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen helper.execute(); 2579ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen } 2580ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen numInserted = len; 2581ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen db.setTransactionSuccessful(); 2582ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen } finally { 2583ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen db.endTransaction(); 2584ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen helper.close(); 2585ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen } 2586ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen getContext().getContentResolver().notifyChange(uri, null); 2587ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen return numInserted; 2588ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen } 2589ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen 259010af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen private long insertDirectory(DatabaseHelper helper, SQLiteDatabase db, String path) { 259110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen if (LOCAL_LOGV) Log.v(TAG, "inserting directory " + path); 2592ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood ContentValues values = new ContentValues(); 2593ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood values.put(FileColumns.FORMAT, MtpConstants.FORMAT_ASSOCIATION); 2594ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood values.put(FileColumns.DATA, path); 259510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen values.put(FileColumns.PARENT, getParent(helper, db, path)); 25969be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood values.put(FileColumns.STORAGE_ID, getStorageId(path)); 2597f2921d9af0a43c4be56a88990b55efe86fc7bb29Mike Lockwood File file = new File(path); 2598f2921d9af0a43c4be56a88990b55efe86fc7bb29Mike Lockwood if (file.exists()) { 2599f2921d9af0a43c4be56a88990b55efe86fc7bb29Mike Lockwood values.put(FileColumns.DATE_MODIFIED, file.lastModified() / 1000); 2600f2921d9af0a43c4be56a88990b55efe86fc7bb29Mike Lockwood } 260110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumInserts++; 2602ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood long rowId = db.insert("files", FileColumns.DATE_MODIFIED, values); 2603ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood sendObjectAdded(rowId); 2604ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood return rowId; 2605ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood } 2606ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood 260710af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen private long getParent(DatabaseHelper helper, SQLiteDatabase db, String path) { 2608b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood int lastSlash = path.lastIndexOf('/'); 2609b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood if (lastSlash > 0) { 2610b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood String parentPath = path.substring(0, lastSlash); 26119be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood for (int i = 0; i < mExternalStoragePaths.length; i++) { 26129be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood if (parentPath.equals(mExternalStoragePaths[i])) { 26139be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood return 0; 26149be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood } 2615b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } 26167f36494e085c26c69cd5925e54028822025eff29Marco Nelissen Long cid = mDirectoryCache.get(parentPath); 26177f36494e085c26c69cd5925e54028822025eff29Marco Nelissen if (cid != null) { 26187f36494e085c26c69cd5925e54028822025eff29Marco Nelissen if (LOCAL_LOGV) Log.v(TAG, "Returning cached entry for " + parentPath); 26197f36494e085c26c69cd5925e54028822025eff29Marco Nelissen return cid; 26207f36494e085c26c69cd5925e54028822025eff29Marco Nelissen } 26217f36494e085c26c69cd5925e54028822025eff29Marco Nelissen 2622f7cc647081f0421c0247de275fa0754b29938c07Mike Lockwood // Use "LIKE" instead of "=" on case insensitive file systems so we do a 2623f7cc647081f0421c0247de275fa0754b29938c07Mike Lockwood // case insensitive match when looking for parent directory. 26247f36494e085c26c69cd5925e54028822025eff29Marco Nelissen // TODO: investigate whether a "nocase" constraint on the column and 26257f36494e085c26c69cd5925e54028822025eff29Marco Nelissen // using "=" would give the same result faster. 2626f7cc647081f0421c0247de275fa0754b29938c07Mike Lockwood String selection = (mCaseInsensitivePaths ? MediaStore.MediaColumns.DATA + " LIKE ?" 2627a9bb89771934314157dd26253195dc16bddc2cfaDongwon Kang // search only directories. 262810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen + " AND format=" + MtpConstants.FORMAT_ASSOCIATION 2629f7cc647081f0421c0247de275fa0754b29938c07Mike Lockwood : MediaStore.MediaColumns.DATA + "=?"); 2630b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood String [] selargs = { parentPath }; 263110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumQueries++; 26327f36494e085c26c69cd5925e54028822025eff29Marco Nelissen Cursor c = db.query("files", sIdOnlyColumn, selection, selargs, null, null, null); 2633b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood try { 26347f36494e085c26c69cd5925e54028822025eff29Marco Nelissen long id; 2635b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood if (c == null || c.getCount() == 0) { 2636b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood // parent isn't in the database - so add it 263710af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen id = insertDirectory(helper, db, parentPath); 26387f36494e085c26c69cd5925e54028822025eff29Marco Nelissen if (LOCAL_LOGV) Log.v(TAG, "Inserted " + parentPath); 2639b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } else { 2640b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood c.moveToFirst(); 26417f36494e085c26c69cd5925e54028822025eff29Marco Nelissen id = c.getLong(0); 26427f36494e085c26c69cd5925e54028822025eff29Marco Nelissen if (LOCAL_LOGV) Log.v(TAG, "Queried " + parentPath); 2643b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } 26447f36494e085c26c69cd5925e54028822025eff29Marco Nelissen mDirectoryCache.put(parentPath, id); 26457f36494e085c26c69cd5925e54028822025eff29Marco Nelissen return id; 2646b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } finally { 2647b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood if (c != null) c.close(); 2648b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } 2649b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } else { 2650b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood return 0; 2651b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } 2652b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } 2653b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 26549be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood private int getStorageId(String path) { 26559be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood for (int i = 0; i < mExternalStoragePaths.length; i++) { 26569be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood String test = mExternalStoragePaths[i]; 26579be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood if (path.startsWith(test)) { 26589be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood int length = test.length(); 26599be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood if (path.length() == length || path.charAt(length) == '/') { 26609be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood return MtpStorage.getStorageId(i); 26619be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood } 26629be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood } 26639be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood } 26649be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood // default to primary storage 26659be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood return MtpStorage.getStorageId(0); 26669be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood } 26679be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood 266810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen private long insertFile(DatabaseHelper helper, Uri uri, ContentValues initialValues, int mediaType, 2669afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood boolean notify) { 267010af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen SQLiteDatabase db = helper.getWritableDatabase(); 2671afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood ContentValues values = null; 2672afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 2673afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood switch (mediaType) { 2674afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood case FileColumns.MEDIA_TYPE_IMAGE: { 267510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen values = ensureFile(helper.mInternal, initialValues, ".jpg", "DCIM/Camera"); 2676afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 2677afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values.put(MediaStore.MediaColumns.DATE_ADDED, System.currentTimeMillis() / 1000); 2678afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood String data = values.getAsString(MediaColumns.DATA); 2679afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (! values.containsKey(MediaColumns.DISPLAY_NAME)) { 2680afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood computeDisplayName(data, values); 2681afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2682afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood computeTakenTime(values); 2683afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood break; 2684afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2685afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 2686afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood case FileColumns.MEDIA_TYPE_AUDIO: { 2687afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // SQLite Views are read-only, so we need to deconstruct this 2688afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // insert and do inserts into the underlying tables. 2689afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // If doing this here turns out to be a performance bottleneck, 2690afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // consider moving this to native code and using triggers on 2691afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // the view. 2692afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values = new ContentValues(initialValues); 2693afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 26942658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen String albumartist = values.getAsString(MediaStore.Audio.Media.ALBUM_ARTIST); 26952658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen String compilation = values.getAsString(MediaStore.Audio.Media.COMPILATION); 26962658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen values.remove(MediaStore.Audio.Media.COMPILATION); 26972658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen 2698afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // Insert the artist into the artist table and remove it from 2699afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // the input values 2700afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood Object so = values.get("artist"); 2701afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood String s = (so == null ? "" : so.toString()); 2702afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values.remove("artist"); 2703afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood long artistRowId; 270410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen HashMap<String, Long> artistCache = helper.mArtistCache; 2705801ba04ac37ee06dccb8bf4081b29a162795e3a6Mike Lockwood String path = values.getAsString(MediaStore.MediaColumns.DATA); 2706afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood synchronized(artistCache) { 2707afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood Long temp = artistCache.get(s); 2708afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (temp == null) { 270910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen artistRowId = getKeyIdForName(helper, db, 271010af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen "artists", "artist_key", "artist", 2711afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood s, s, path, 0, null, artistCache, uri); 2712afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } else { 2713afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood artistRowId = temp.longValue(); 2714afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2715afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2716afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood String artist = s; 2717afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 2718afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // Do the same for the album field 2719afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood so = values.get("album"); 2720afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood s = (so == null ? "" : so.toString()); 2721afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values.remove("album"); 2722afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood long albumRowId; 272310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen HashMap<String, Long> albumCache = helper.mAlbumCache; 2724afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood synchronized(albumCache) { 27252658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen int albumhash = 0; 27262658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen if (albumartist != null) { 27272658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen albumhash = albumartist.hashCode(); 27282658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen } else if (compilation != null && compilation.equals("1")) { 27292658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen // nothing to do, hash already set 27302658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen } else { 27312658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen albumhash = path.substring(0, path.lastIndexOf('/')).hashCode(); 27322658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen } 2733afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood String cacheName = s + albumhash; 2734afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood Long temp = albumCache.get(cacheName); 2735afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (temp == null) { 273610af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen albumRowId = getKeyIdForName(helper, db, 273710af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen "albums", "album_key", "album", 2738afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood s, cacheName, path, albumhash, artist, albumCache, uri); 2739afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } else { 2740afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood albumRowId = temp; 2741afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2742afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 27435d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood 2744afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values.put("artist_id", Integer.toString((int)artistRowId)); 2745afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values.put("album_id", Integer.toString((int)albumRowId)); 2746afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood so = values.getAsString("title"); 2747afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood s = (so == null ? "" : so.toString()); 2748afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values.put("title_key", MediaStore.Audio.keyFor(s)); 2749afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // do a final trim of the title, in case it started with the special 2750afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // "sort first" character (ascii \001) 2751afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values.remove("title"); 2752afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values.put("title", s.trim()); 2753b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 2754801ba04ac37ee06dccb8bf4081b29a162795e3a6Mike Lockwood computeDisplayName(values.getAsString(MediaStore.MediaColumns.DATA), values); 2755afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood break; 2756afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2757afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 2758afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood case FileColumns.MEDIA_TYPE_VIDEO: { 275910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen values = ensureFile(helper.mInternal, initialValues, ".3gp", "video"); 2760801ba04ac37ee06dccb8bf4081b29a162795e3a6Mike Lockwood String data = values.getAsString(MediaStore.MediaColumns.DATA); 2761afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood computeDisplayName(data, values); 2762afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood computeTakenTime(values); 2763afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood break; 2764afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2765afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2766afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 2767afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (values == null) { 2768afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values = new ContentValues(initialValues); 2769afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2770fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood // compute bucket_id and bucket_display_name for all files 2771afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood String path = values.getAsString(MediaStore.MediaColumns.DATA); 2772fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood if (path != null) { 2773fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood computeBucketValues(path, values); 2774fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood } 2775fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood values.put(MediaStore.MediaColumns.DATE_ADDED, System.currentTimeMillis() / 1000); 2776afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 2777afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood long rowId = 0; 2778afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood Integer i = values.getAsInteger( 2779afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood MediaStore.MediaColumns.MEDIA_SCANNER_NEW_OBJECT_ID); 2780afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (i != null) { 2781afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood rowId = i.intValue(); 2782afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values = new ContentValues(values); 2783afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values.remove(MediaStore.MediaColumns.MEDIA_SCANNER_NEW_OBJECT_ID); 2784afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2785afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 2786afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood String title = values.getAsString(MediaStore.MediaColumns.TITLE); 27873572ac7fc911cda5e4ac60af9455820a7ddf6593Marco Nelissen if (title == null && path != null) { 2788c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood title = MediaFile.getFileTitle(path); 2789c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood } 2790c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood values.put(FileColumns.TITLE, title); 2791c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood 2792afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood String mimeType = values.getAsString(MediaStore.MediaColumns.MIME_TYPE); 2793afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood Integer formatObject = values.getAsInteger(FileColumns.FORMAT); 2794c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood int format = (formatObject == null ? 0 : formatObject.intValue()); 2795c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood if (format == 0) { 279663b4ed85f500e23297ad5eb530318e06b9ab2289Dongwon Kang if (TextUtils.isEmpty(path)) { 2797c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood // special case device created playlists 2798afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (mediaType == FileColumns.MEDIA_TYPE_PLAYLIST) { 2799c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood values.put(FileColumns.FORMAT, MtpConstants.FORMAT_ABSTRACT_AV_PLAYLIST); 2800c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood // create a file path for the benefit of MTP 28019be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood path = mExternalStoragePaths[0] 2802afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + "/Playlists/" + values.getAsString(Audio.Playlists.NAME); 2803c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood values.put(MediaStore.MediaColumns.DATA, path); 280410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen values.put(FileColumns.PARENT, getParent(helper, db, path)); 2805c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood } else { 280663b4ed85f500e23297ad5eb530318e06b9ab2289Dongwon Kang Log.e(TAG, "path is empty in insertFile()"); 2807c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood } 2808c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood } else { 2809c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood format = MediaFile.getFormatCode(path, mimeType); 2810c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood } 2811c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood } 2812c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood if (format != 0) { 2813c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood values.put(FileColumns.FORMAT, format); 2814c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood if (mimeType == null) { 2815c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood mimeType = MediaFile.getMimeTypeForFormatCode(format); 2816c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood } 2817c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood } 2818c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood 2819801ba04ac37ee06dccb8bf4081b29a162795e3a6Mike Lockwood if (mimeType == null && path != null) { 2820c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood mimeType = MediaFile.getMimeTypeForFile(path); 2821c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood } 2822c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood if (mimeType != null) { 2823c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood values.put(FileColumns.MIME_TYPE, mimeType); 2824afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 2825f1f6a9e343033de33fc748f659b9221f8d5b06e1Mike Lockwood if (mediaType == FileColumns.MEDIA_TYPE_NONE && !MediaScanner.isNoMediaPath(path)) { 2826afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood int fileType = MediaFile.getFileTypeForMimeType(mimeType); 2827afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (MediaFile.isAudioFileType(fileType)) { 2828afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood mediaType = FileColumns.MEDIA_TYPE_AUDIO; 2829afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } else if (MediaFile.isVideoFileType(fileType)) { 2830afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood mediaType = FileColumns.MEDIA_TYPE_VIDEO; 2831afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } else if (MediaFile.isImageFileType(fileType)) { 2832afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood mediaType = FileColumns.MEDIA_TYPE_IMAGE; 2833afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } else if (MediaFile.isPlayListFileType(fileType)) { 2834afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood mediaType = FileColumns.MEDIA_TYPE_PLAYLIST; 2835afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2836afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2837c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood } 2838afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values.put(FileColumns.MEDIA_TYPE, mediaType); 2839c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood 2840afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (rowId == 0) { 2841afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (mediaType == FileColumns.MEDIA_TYPE_PLAYLIST) { 28423572ac7fc911cda5e4ac60af9455820a7ddf6593Marco Nelissen String name = values.getAsString(Audio.Playlists.NAME); 2843282dc90a0e201d992cdd0d0176028da6a565f9d5Mike Lockwood if (name == null && path == null) { 2844282dc90a0e201d992cdd0d0176028da6a565f9d5Mike Lockwood // MediaScanner will compute the name from the path if we have one 2845afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood throw new IllegalArgumentException( 2846282dc90a0e201d992cdd0d0176028da6a565f9d5Mike Lockwood "no name was provided when inserting abstract playlist"); 2847afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2848afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } else { 2849a36cfaef630ef5df7bef80b25f6bd493d040c7e4Brian Muramatsu if (path == null) { 2850afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // path might be null for playlists created on the device 2851afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // or transfered via MTP 2852afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood throw new IllegalArgumentException( 2853afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "no path was provided when inserting new file"); 2854afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2855e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2856b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 2857f2921d9af0a43c4be56a88990b55efe86fc7bb29Mike Lockwood // make sure modification date and size are set 2858f2921d9af0a43c4be56a88990b55efe86fc7bb29Mike Lockwood if (path != null) { 2859f2921d9af0a43c4be56a88990b55efe86fc7bb29Mike Lockwood File file = new File(path); 2860f2921d9af0a43c4be56a88990b55efe86fc7bb29Mike Lockwood if (file.exists()) { 2861f2921d9af0a43c4be56a88990b55efe86fc7bb29Mike Lockwood values.put(FileColumns.DATE_MODIFIED, file.lastModified() / 1000); 286216dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood values.put(FileColumns.SIZE, file.length()); 2863e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 28645d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood } 2865b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 2866afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood Long parent = values.getAsLong(FileColumns.PARENT); 28675d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood if (parent == null) { 2868e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (path != null) { 286910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen long parentId = getParent(helper, db, path); 287016dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood values.put(FileColumns.PARENT, parentId); 2871e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 28729be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood } 28739be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood Integer storage = values.getAsInteger(FileColumns.STORAGE_ID); 28749be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood if (storage == null) { 28759be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood int storageId = getStorageId(path); 28769be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood values.put(FileColumns.STORAGE_ID, storageId); 28775d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood } 2878b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 287910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumInserts++; 2880afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood rowId = db.insert("files", FileColumns.DATE_MODIFIED, values); 2881afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (LOCAL_LOGV) Log.v(TAG, "insertFile: values=" + values + " returned: " + rowId); 2882afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 288310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen if (rowId != -1 && notify) { 2884afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood sendObjectAdded(rowId); 2885afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 28865d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood } else { 288710af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumUpdates++; 288816dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood db.update("files", values, FileColumns._ID + "=?", 2889afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood new String[] { Long.toString(rowId) }); 28905d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood } 2891afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 2892afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood return rowId; 28931717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood } 28941717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood 289510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen private Cursor getObjectReferences(DatabaseHelper helper, SQLiteDatabase db, int handle) { 289610af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumQueries++; 2897a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen Cursor c = db.query("files", sMediaTableColumns, "_id=?", 2898e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood new String[] { Integer.toString(handle) }, 2899e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood null, null, null); 2900e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood try { 2901e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (c != null && c.moveToNext()) { 2902afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood long playlistId = c.getLong(0); 2903afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood int mediaType = c.getInt(1); 2904afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (mediaType != FileColumns.MEDIA_TYPE_PLAYLIST) { 2905e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood // we only support object references for playlist objects 2906e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood return null; 2907e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 290810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumQueries++; 2909e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood return db.rawQuery(OBJECT_REFERENCES_QUERY, 2910afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood new String[] { Long.toString(playlistId) } ); 2911e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2912e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } finally { 2913e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (c != null) { 2914e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood c.close(); 2915e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2916e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2917e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood return null; 2918e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2919e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood 292010af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen private int setObjectReferences(DatabaseHelper helper, SQLiteDatabase db, 292110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen int handle, ContentValues values[]) { 2922e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood // first look up the media table and media ID for the object 2923e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood long playlistId = 0; 292410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumQueries++; 2925a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen Cursor c = db.query("files", sMediaTableColumns, "_id=?", 2926e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood new String[] { Integer.toString(handle) }, 2927e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood null, null, null); 2928e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood try { 2929e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (c != null && c.moveToNext()) { 2930afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood int mediaType = c.getInt(1); 2931afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (mediaType != FileColumns.MEDIA_TYPE_PLAYLIST) { 2932e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood // we only support object references for playlist objects 2933e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood return 0; 2934e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2935afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood playlistId = c.getLong(0); 2936e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2937e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } finally { 2938e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (c != null) { 2939e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood c.close(); 2940e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2941e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2942e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (playlistId == 0) { 2943e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood return 0; 2944e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2945e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood 2946e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood // next delete any existing entries 294710af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumDeletes++; 294810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen db.delete("audio_playlists_map", "playlist_id=?", 2949e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood new String[] { Long.toString(playlistId) }); 2950e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood 2951e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood // finally add the new entries 2952e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood int count = values.length; 2953e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood int added = 0; 2954e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood ContentValues[] valuesList = new ContentValues[count]; 2955e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood for (int i = 0; i < count; i++) { 2956e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood // convert object ID to audio ID 2957e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood long audioId = 0; 2958e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood long objectId = values[i].getAsLong(MediaStore.MediaColumns._ID); 295910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumQueries++; 2960a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen c = db.query("files", sMediaTableColumns, "_id=?", 2961e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood new String[] { Long.toString(objectId) }, 2962e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood null, null, null); 2963e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood try { 2964e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (c != null && c.moveToNext()) { 2965afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood int mediaType = c.getInt(1); 296650d8650456d93e2107b9163e119c2eb9de73f804Mike Lockwood if (mediaType != FileColumns.MEDIA_TYPE_AUDIO) { 2967e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood // we only allow audio files in playlists, so skip 2968e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood continue; 2969e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2970afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood audioId = c.getLong(0); 2971e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2972e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } finally { 2973e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (c != null) { 2974e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood c.close(); 2975e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2976e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2977e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (audioId != 0) { 2978e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood ContentValues v = new ContentValues(); 2979e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood v.put(MediaStore.Audio.Playlists.Members.PLAYLIST_ID, playlistId); 2980e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood v.put(MediaStore.Audio.Playlists.Members.AUDIO_ID, audioId); 2981a08bc533a5f7bf9aea49b25a549b4f5b3c14f47dMike Lockwood v.put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, added); 2982a08bc533a5f7bf9aea49b25a549b4f5b3c14f47dMike Lockwood valuesList[added++] = v; 2983e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2984e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2985e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (added < count) { 2986e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood // we weren't able to find everything on the list, so lets resize the array 2987e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood // and pass what we have. 2988e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood ContentValues[] newValues = new ContentValues[added]; 2989e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood System.arraycopy(valuesList, 0, newValues, 0, added); 2990e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood valuesList = newValues; 2991e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2992e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood return playlistBulkInsert(db, 2993e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood Audio.Playlists.Members.getContentUri(EXTERNAL_VOLUME, playlistId), 2994e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood valuesList); 2995e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2996e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood 2997b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood private static final String[] GENRE_LOOKUP_PROJECTION = new String[] { 2998b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood Audio.Genres._ID, // 0 2999b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood Audio.Genres.NAME, // 1 3000b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood }; 3001b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood 3002b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood private void updateGenre(long rowId, String genre) { 3003b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood Uri uri = null; 3004b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood Cursor cursor = null; 3005b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood Uri genresUri = MediaStore.Audio.Genres.getContentUri("external"); 3006b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood try { 3007b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood // see if the genre already exists 3008b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood cursor = query(genresUri, GENRE_LOOKUP_PROJECTION, MediaStore.Audio.Genres.NAME + "=?", 3009b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood new String[] { genre }, null); 3010b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood if (cursor == null || cursor.getCount() == 0) { 3011b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood // genre does not exist, so create the genre in the genre table 3012b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood ContentValues values = new ContentValues(); 3013b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood values.put(MediaStore.Audio.Genres.NAME, genre); 3014b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood uri = insert(genresUri, values); 3015b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood } else { 3016b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood // genre already exists, so compute its Uri 3017b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood cursor.moveToNext(); 3018b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood uri = ContentUris.withAppendedId(genresUri, cursor.getLong(0)); 3019b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood } 3020b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood if (uri != null) { 3021b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood uri = Uri.withAppendedPath(uri, MediaStore.Audio.Genres.Members.CONTENT_DIRECTORY); 3022b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood } 3023b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood } finally { 3024b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood // release the cursor if it exists 3025b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood if (cursor != null) { 3026b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood cursor.close(); 3027b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood } 3028b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood } 3029b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood 3030b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood if (uri != null) { 3031b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood // add entry to audio_genre_map 3032b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood ContentValues values = new ContentValues(); 3033b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood values.put(MediaStore.Audio.Genres.Members.AUDIO_ID, Long.valueOf(rowId)); 3034b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood insert(uri, values); 3035b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood } 3036b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood } 3037b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood 30385d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood private Uri insertInternal(Uri uri, int match, ContentValues initialValues) { 3039702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long rowId; 3040702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3041d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood if (LOCAL_LOGV) Log.v(TAG, "insertInternal: "+uri+", initValues="+initialValues); 3042702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // handle MEDIA_SCANNER before calling getDatabaseForUri() 3043702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (match == MEDIA_SCANNER) { 3044bc442ef681710cca3d8eb1a57d6e81471c9987c0Mike Lockwood mMediaScannerVolume = initialValues.getAsString(MediaStore.MEDIA_SCANNER_VOLUME); 304510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen DatabaseHelper database = getDatabaseForUri( 304610af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen Uri.parse("content://media/" + mMediaScannerVolume + "/audio")); 304710af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen if (database == null) { 304810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen Log.w(TAG, "no database for scanned volume " + mMediaScannerVolume); 304910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen } else { 305010af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen database.mScanStartTime = SystemClock.currentTimeMicro(); 305110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen } 3052702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return MediaStore.getMediaScannerUri(); 3053702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3054702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3055b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood String genre = null; 305638b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen String path = null; 3057b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood if (initialValues != null) { 3058b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood genre = initialValues.getAsString(Audio.AudioColumns.GENRE); 3059b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood initialValues.remove(Audio.AudioColumns.GENRE); 306038b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen path = initialValues.getAsString(MediaStore.MediaColumns.DATA); 3061b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood } 3062b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood 306338b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen 3064702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Uri newUri = null; 306510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen DatabaseHelper helper = getDatabaseForUri(uri); 306610af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen if (helper == null && match != VOLUMES && match != MTP_CONNECTED) { 3067702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException( 3068702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Unknown URI: " + uri); 3069702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 307010af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen 3071819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood SQLiteDatabase db = ((match == VOLUMES || match == MTP_CONNECTED) ? null 307210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen : helper.getWritableDatabase()); 3073702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3074702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (match) { 3075702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA: { 307610af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen rowId = insertFile(helper, uri, initialValues, FileColumns.MEDIA_TYPE_IMAGE, true); 3077702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 3078702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId( 3079702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Images.Media.getContentUri(uri.getPathSegments().get(0)), rowId); 3080702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3081702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3082702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3083702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3084b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // This will be triggered by requestMediaThumbnail (see getThumbnailUri) 3085702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_THUMBNAILS: { 308610af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen ContentValues values = ensureFile(helper.mInternal, initialValues, ".jpg", 3087b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "DCIM/.thumbnails"); 308810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumInserts++; 3089702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert("thumbnails", "name", values); 3090702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 3091702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(Images.Thumbnails. 3092702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 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 3097b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // This is currently only used by MICRO_KIND video thumbnail (see getThumbnailUri) 3098b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case VIDEO_THUMBNAILS: { 309910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen ContentValues values = ensureFile(helper.mInternal, initialValues, ".jpg", 3100b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "DCIM/.thumbnails"); 310110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumInserts++; 3102b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen rowId = db.insert("videothumbnails", "name", values); 3103b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (rowId > 0) { 3104b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen newUri = ContentUris.withAppendedId(Video.Thumbnails. 3105b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen getContentUri(uri.getPathSegments().get(0)), rowId); 3106b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 3107b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen break; 3108b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 3109b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 3110702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA: { 311110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen rowId = insertFile(helper, uri, initialValues, FileColumns.MEDIA_TYPE_AUDIO, true); 3112702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 3113702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(Audio.Media.getContentUri(uri.getPathSegments().get(0)), rowId); 3114b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood if (genre != null) { 3115b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood updateGenre(rowId, genre); 3116b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood } 3117702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3118702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3119702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3120702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3121702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES: { 3122702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Long audioId = Long.parseLong(uri.getPathSegments().get(2)); 3123bc442ef681710cca3d8eb1a57d6e81471c9987c0Mike Lockwood ContentValues values = new ContentValues(initialValues); 3124702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(Audio.Genres.Members.AUDIO_ID, audioId); 312510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumInserts++; 3126ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen rowId = db.insert("audio_genres_map", "genre_id", values); 3127702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 3128702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(uri, rowId); 3129702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3130702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3131702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3132702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3133702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS: { 3134702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Long audioId = Long.parseLong(uri.getPathSegments().get(2)); 3135bc442ef681710cca3d8eb1a57d6e81471c9987c0Mike Lockwood ContentValues values = new ContentValues(initialValues); 3136702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(Audio.Playlists.Members.AUDIO_ID, audioId); 313710af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumInserts++; 3138702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert("audio_playlists_map", "playlist_id", 3139702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values); 3140702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 3141702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(uri, rowId); 3142702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3143702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3144702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3145702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3146702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES: { 314710af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumInserts++; 3148bc442ef681710cca3d8eb1a57d6e81471c9987c0Mike Lockwood rowId = db.insert("audio_genres", "audio_id", initialValues); 3149702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 3150702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(Audio.Genres.getContentUri(uri.getPathSegments().get(0)), rowId); 3151702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3152702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3153702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3154702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3155702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID_MEMBERS: { 3156702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Long genreId = Long.parseLong(uri.getPathSegments().get(3)); 3157bc442ef681710cca3d8eb1a57d6e81471c9987c0Mike Lockwood ContentValues values = new ContentValues(initialValues); 3158702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(Audio.Genres.Members.GENRE_ID, genreId); 315910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumInserts++; 3160702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert("audio_genres_map", "genre_id", values); 3161702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 3162702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(uri, rowId); 3163702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3164702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3165702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3166702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3167702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS: { 3168bc442ef681710cca3d8eb1a57d6e81471c9987c0Mike Lockwood ContentValues values = new ContentValues(initialValues); 3169702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(MediaStore.Audio.Playlists.DATE_ADDED, System.currentTimeMillis() / 1000); 317010af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen rowId = insertFile(helper, uri, values, FileColumns.MEDIA_TYPE_PLAYLIST, true); 3171702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 3172702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(Audio.Playlists.getContentUri(uri.getPathSegments().get(0)), rowId); 3173702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3174702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3175702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3176702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3177702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID: 3178702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS: { 3179702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Long playlistId = Long.parseLong(uri.getPathSegments().get(3)); 3180bc442ef681710cca3d8eb1a57d6e81471c9987c0Mike Lockwood ContentValues values = new ContentValues(initialValues); 3181702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(Audio.Playlists.Members.PLAYLIST_ID, playlistId); 318210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumInserts++; 3183ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen rowId = db.insert("audio_playlists_map", "playlist_id", values); 3184702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 3185702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(uri, rowId); 3186702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3187702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3188702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3189702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3190702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA: { 319110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen rowId = insertFile(helper, uri, initialValues, FileColumns.MEDIA_TYPE_VIDEO, true); 3192702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 3193b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen newUri = ContentUris.withAppendedId(Video.Media.getContentUri( 3194b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen uri.getPathSegments().get(0)), rowId); 3195702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3196702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3197702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3198702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3199c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood case AUDIO_ALBUMART: { 320010af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen if (helper.mInternal) { 3201702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException("no internal album art allowed"); 3202702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3203bc442ef681710cca3d8eb1a57d6e81471c9987c0Mike Lockwood ContentValues values = null; 3204702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 3205bc442ef681710cca3d8eb1a57d6e81471c9987c0Mike Lockwood values = ensureFile(false, initialValues, "", ALBUM_THUMB_FOLDER); 3206702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } catch (IllegalStateException ex) { 3207702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // probably no more room to store albumthumbs 3208bc442ef681710cca3d8eb1a57d6e81471c9987c0Mike Lockwood values = initialValues; 3209702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 321010af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumInserts++; 3211801ba04ac37ee06dccb8bf4081b29a162795e3a6Mike Lockwood rowId = db.insert("album_art", MediaStore.MediaColumns.DATA, values); 3212702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 3213702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(uri, rowId); 3214702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3215702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3216c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood } 3217702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3218702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VOLUMES: 3219bc442ef681710cca3d8eb1a57d6e81471c9987c0Mike Lockwood return attachVolume(initialValues.getAsString("name")); 3220702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3221819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood case MTP_CONNECTED: 322234be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood synchronized (mMtpServiceConnection) { 322334be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood if (mMtpService == null) { 322434be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood Context context = getContext(); 322534be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood // MTP is connected, so grab a connection to MtpService 322634be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood context.bindService(new Intent(context, MtpService.class), 322734be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood mMtpServiceConnection, Context.BIND_AUTO_CREATE); 322834be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood } 322934be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood } 3230819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood break; 3231819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood 3232afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood case FILES: 323310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen rowId = insertFile(helper, uri, initialValues, 3234bc442ef681710cca3d8eb1a57d6e81471c9987c0Mike Lockwood FileColumns.MEDIA_TYPE_NONE, true); 3235fc824ed365b03ae272a3241b202367b1bdec18bcMike Lockwood if (rowId > 0) { 3236fc824ed365b03ae272a3241b202367b1bdec18bcMike Lockwood newUri = Files.getContentUri(uri.getPathSegments().get(0), rowId); 323710af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen if (initialValues.getAsInteger(MediaStore.Files.FileColumns.FORMAT) 323810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen == MtpConstants.FORMAT_ASSOCIATION) { 323938b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen mDirectoryCache.put(path, rowId); 324010af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen } 3241fc824ed365b03ae272a3241b202367b1bdec18bcMike Lockwood } 3242fc824ed365b03ae272a3241b202367b1bdec18bcMike Lockwood break; 3243fc824ed365b03ae272a3241b202367b1bdec18bcMike Lockwood 3244e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood case MTP_OBJECTS: 3245afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // don't send a notification if the insert originated from MTP 324610af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen rowId = insertFile(helper, uri, initialValues, 3247bc442ef681710cca3d8eb1a57d6e81471c9987c0Mike Lockwood FileColumns.MEDIA_TYPE_NONE, false); 3248afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (rowId > 0) { 3249afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood newUri = Files.getMtpObjectsUri(uri.getPathSegments().get(0), rowId); 32505d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood } 32515d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood break; 32525d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood 3253702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project default: 3254702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException("Invalid URI " + uri); 3255702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3256702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 325738b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen if (path != null && path.toLowerCase(Locale.US).endsWith("/.nomedia")) { 325838b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen // need to set the media_type of all the files below this folder to 0 325938b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen processNewNoMediaPath(helper, db, path); 326038b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen } 3261702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return newUri; 3262702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3263702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 326438b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen /* 326538b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen * Sets the media type of all files below the newly added .nomedia file or 326638b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen * hidden folder to 0, so the entries no longer appear in e.g. the audio and 326738b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen * images views. 326838b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen * 326938b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen * @param path The path to the new .nomedia file or hidden directory 327038b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen */ 327138b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen private void processNewNoMediaPath(DatabaseHelper helper, SQLiteDatabase db, String path) { 327238b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen File nomedia = new File(path); 327338b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen if (nomedia.exists()) { 327438b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen // only do this if the file actually exists, so we don't get tricked 327538b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen // by someone just inserting a .nomedia entry into the database 327638b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen String hiddenroot = nomedia.isDirectory() ? path : nomedia.getParent(); 327738b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen ContentValues mediatype = new ContentValues(); 327838b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen mediatype.put("media_type", 0); 327938b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen int numrows = db.update("files", mediatype, "_data LIKE ?", new String[] { hiddenroot + "/%"}); 328038b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen helper.mNumUpdates += numrows; 328138b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen ContentResolver res = getContext().getContentResolver(); 328238b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen res.notifyChange(Uri.parse("content://media/"), null); 328338b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen } 328438b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen } 328538b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen 328638b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen /* 328738b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen * Rescan files for missing metadata and set their type accordingly. 328838b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen * There is code for detecting the removal of a nomedia file or renaming of 328938b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen * a directory from hidden to non-hidden in the MediaScanner and MtpDatabase, 329038b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen * both of which call here. 329138b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen */ 329238b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen private void processRemovedNoMediaPath(final String path) { 329338b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen final DatabaseHelper helper; 329438b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen if (path.startsWith(mExternalStoragePaths[0])) { 329538b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen helper = getDatabaseForUri(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI); 329638b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen } else { 329738b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen helper = getDatabaseForUri(MediaStore.Audio.Media.INTERNAL_CONTENT_URI); 329838b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen } 329938b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen SQLiteDatabase db = helper.getWritableDatabase(); 330038b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen new ScannerClient(getContext(), db, path); 330138b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen } 330238b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen 330338b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen private static final class ScannerClient implements MediaScannerConnectionClient { 330438b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen String mPath = null; 330538b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen MediaScannerConnection mScannerConnection; 330638b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen SQLiteDatabase mDb; 330738b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen 330838b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen public ScannerClient(Context context, SQLiteDatabase db, String path) { 330938b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen mDb = db; 331038b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen mPath = path; 331138b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen mScannerConnection = new MediaScannerConnection(context, this); 331238b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen mScannerConnection.connect(); 331338b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen } 331438b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen 331538b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen @Override 331638b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen public void onMediaScannerConnected() { 331738b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen Cursor c = mDb.query("files", openFileColumns, "_data like ?", 331838b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen new String[] { mPath + "/%"}, null, null, null); 331938b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen while (c.moveToNext()) { 332038b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen String d = c.getString(0); 332138b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen File f = new File(d); 332238b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen if (f.isFile()) { 332338b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen mScannerConnection.scanFile(d, null); 332438b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen } 332538b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen } 332638b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen mScannerConnection.disconnect(); 332738b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen c.close(); 332838b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen } 332938b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen 333038b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen @Override 333138b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen public void onScanCompleted(String path, Uri uri) { 333238b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen } 333338b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen } 333438b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen 3335cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen @Override 3336cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) 3337cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen throws OperationApplicationException { 3338cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen 3339cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen // The operations array provides no overall information about the URI(s) being operated 3340cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen // on, so begin a transaction for ALL of the databases. 3341cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen DatabaseHelper ihelper = getDatabaseForUri(MediaStore.Audio.Media.INTERNAL_CONTENT_URI); 3342cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen DatabaseHelper ehelper = getDatabaseForUri(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI); 3343cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen SQLiteDatabase idb = ihelper.getWritableDatabase(); 3344cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen idb.beginTransaction(); 3345cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen SQLiteDatabase edb = null; 3346cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen if (ehelper != null) { 3347cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen edb = ehelper.getWritableDatabase(); 3348cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen edb.beginTransaction(); 3349cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen } 3350cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen try { 3351cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen ContentProviderResult[] result = super.applyBatch(operations); 3352cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen idb.setTransactionSuccessful(); 3353cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen if (edb != null) { 3354cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen edb.setTransactionSuccessful(); 3355cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen } 3356cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen // Rather than sending targeted change notifications for every Uri 3357cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen // affected by the batch operation, just invalidate the entire internal 3358cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen // and external name space. 3359cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen ContentResolver res = getContext().getContentResolver(); 3360cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen res.notifyChange(Uri.parse("content://media/"), null); 3361cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen return result; 3362cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen } finally { 3363cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen idb.endTransaction(); 3364cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen if (edb != null) { 3365cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen edb.endTransaction(); 3366cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen } 3367cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen } 3368cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen } 3369cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen 3370cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen 33719299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen private MediaThumbRequest requestMediaThumbnail(String path, Uri uri, int priority, long magic) { 3372b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen synchronized (mMediaThumbQueue) { 3373e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen MediaThumbRequest req = null; 3374e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen try { 3375e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen req = new MediaThumbRequest( 33769299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen getContext().getContentResolver(), path, uri, priority, magic); 3377e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen mMediaThumbQueue.add(req); 3378e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen // Trigger the handler. 3379e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen Message msg = mThumbHandler.obtainMessage(IMAGE_THUMB); 3380e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen msg.sendToTarget(); 3381e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen } catch (Throwable t) { 3382e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen Log.w(TAG, t); 3383e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen } 3384b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return req; 3385b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 3386b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 3387b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 3388702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private String generateFileName(boolean internal, String preferredExtension, String directoryName) 3389702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project { 3390702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // create a random file 3391702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String name = String.valueOf(System.currentTimeMillis()); 3392702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3393702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (internal) { 3394702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException("Writing to internal storage is not supported."); 3395702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project// return Environment.getDataDirectory() 3396702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project// + "/" + directoryName + "/" + name + preferredExtension; 3397702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 33989be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood return mExternalStoragePaths[0] + "/" + directoryName + "/" + name + preferredExtension; 3399702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3400702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3401702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3402702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private boolean ensureFileExists(String path) { 3403702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File file = new File(path); 3404702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (file.exists()) { 3405702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return true; 3406702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 3407702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // we will not attempt to create the first directory in the path 3408702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // (for example, do not create /sdcard if the SD card is not mounted) 3409702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int secondSlash = path.indexOf('/', 1); 3410702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (secondSlash < 1) return false; 3411702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String directoryPath = path.substring(0, secondSlash); 3412702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File directory = new File(directoryPath); 3413702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!directory.exists()) 3414702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return false; 341517ad80b32f839ccddac3911799ff732d1ca3a006Mike Lockwood file.getParentFile().mkdirs(); 3416702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 341717ad80b32f839ccddac3911799ff732d1ca3a006Mike Lockwood return file.createNewFile(); 3418702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } catch(IOException ioe) { 3419702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Log.e(TAG, "File creation failed", ioe); 3420702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3421702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return false; 3422702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3423702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3424702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3425702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final class GetTableAndWhereOutParameter { 3426702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public String table; 3427702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public String where; 3428702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3429702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3430702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project static final GetTableAndWhereOutParameter sGetTableAndWhereParam = 3431702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project new GetTableAndWhereOutParameter(); 3432702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3433702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private void getTableAndWhere(Uri uri, int match, String userWhere, 3434702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project GetTableAndWhereOutParameter out) { 3435702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String where = null; 3436702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (match) { 34379f02f449f6951b15bb9daaa3fc6e1d648b36b08aGoodwin case IMAGES_MEDIA: 3438afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood out.table = "files"; 3439afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood where = FileColumns.MEDIA_TYPE + "=" + FileColumns.MEDIA_TYPE_IMAGE; 34409f02f449f6951b15bb9daaa3fc6e1d648b36b08aGoodwin break; 34419f02f449f6951b15bb9daaa3fc6e1d648b36b08aGoodwin 3442702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA_ID: 3443afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood out.table = "files"; 3444702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "_id = " + uri.getPathSegments().get(3); 3445702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3446702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3447b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case IMAGES_THUMBNAILS_ID: 3448b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen where = "_id=" + uri.getPathSegments().get(3); 3449b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case IMAGES_THUMBNAILS: 3450b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen out.table = "thumbnails"; 3451b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen break; 3452b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 3453702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA: 3454afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood out.table = "files"; 3455afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood where = FileColumns.MEDIA_TYPE + "=" + FileColumns.MEDIA_TYPE_AUDIO; 3456702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3457702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3458702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID: 3459afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood out.table = "files"; 3460702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "_id=" + uri.getPathSegments().get(3); 3461702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3462702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3463702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES: 3464702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_genres"; 3465702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "audio_id=" + uri.getPathSegments().get(3); 3466702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3467702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3468702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES_ID: 3469702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_genres"; 3470702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "audio_id=" + uri.getPathSegments().get(3) + 3471702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " AND genre_id=" + uri.getPathSegments().get(5); 3472702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3473702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3474702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS: 3475702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_playlists"; 3476702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "audio_id=" + uri.getPathSegments().get(3); 3477702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3478702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3479702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS_ID: 3480702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_playlists"; 3481702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "audio_id=" + uri.getPathSegments().get(3) + 3482702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " AND playlists_id=" + uri.getPathSegments().get(5); 3483702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3484702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3485702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES: 3486702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_genres"; 3487702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3488702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3489702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID: 3490702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_genres"; 3491702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "_id=" + uri.getPathSegments().get(3); 3492702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3493702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3494702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID_MEMBERS: 3495702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_genres"; 3496702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "genre_id=" + uri.getPathSegments().get(3); 3497702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3498702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3499702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS: 3500afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood out.table = "files"; 3501afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood where = FileColumns.MEDIA_TYPE + "=" + FileColumns.MEDIA_TYPE_PLAYLIST; 3502702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3503702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3504702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID: 3505afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood out.table = "files"; 3506702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "_id=" + uri.getPathSegments().get(3); 3507702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3508702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3509702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS: 3510702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_playlists_map"; 3511702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "playlist_id=" + uri.getPathSegments().get(3); 3512702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3513702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3514702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS_ID: 3515702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_playlists_map"; 3516702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "playlist_id=" + uri.getPathSegments().get(3) + 3517702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " AND _id=" + uri.getPathSegments().get(5); 3518702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3519702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3520702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ALBUMART_ID: 3521702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "album_art"; 3522702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "album_id=" + uri.getPathSegments().get(3); 3523702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3524702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3525702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA: 3526afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood out.table = "files"; 3527afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood where = FileColumns.MEDIA_TYPE + "=" + FileColumns.MEDIA_TYPE_VIDEO; 3528702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3529702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3530702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA_ID: 3531afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood out.table = "files"; 3532702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "_id=" + uri.getPathSegments().get(3); 3533702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3534702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3535b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case VIDEO_THUMBNAILS_ID: 3536b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen where = "_id=" + uri.getPathSegments().get(3); 3537b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case VIDEO_THUMBNAILS: 3538b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen out.table = "videothumbnails"; 3539b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen break; 3540b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 354116dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood case FILES_ID: 3542e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood case MTP_OBJECTS_ID: 35431717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood where = "_id=" + uri.getPathSegments().get(2); 354416dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood case FILES: 3545e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood case MTP_OBJECTS: 354616dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood out.table = "files"; 35471717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood break; 35481717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood 3549702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project default: 3550702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException( 3551702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Unknown or unsupported URL: " + uri.toString()); 3552702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3553702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3554702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Add in the user requested WHERE clause, if needed 3555702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!TextUtils.isEmpty(userWhere)) { 3556702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!TextUtils.isEmpty(where)) { 3557702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.where = where + " AND (" + userWhere + ")"; 3558702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 3559702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.where = userWhere; 3560702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3561702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 3562702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.where = where; 3563702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3564702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3565702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3566702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 3567702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public int delete(Uri uri, String userWhere, String[] whereArgs) { 3568702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int count; 3569702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int match = URI_MATCHER.match(uri); 3570702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3571702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // handle MEDIA_SCANNER before calling getDatabaseForUri() 3572702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (match == MEDIA_SCANNER) { 3573702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (mMediaScannerVolume == null) { 3574702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return 0; 3575702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 357610af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen DatabaseHelper database = getDatabaseForUri( 357710af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen Uri.parse("content://media/" + mMediaScannerVolume + "/audio")); 357810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen if (database == null) { 357910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen Log.w(TAG, "no database for scanned volume " + mMediaScannerVolume); 358010af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen } else { 358110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen database.mScanStopTime = SystemClock.currentTimeMicro(); 358210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen } 3583702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mMediaScannerVolume = null; 3584702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return 1; 3585702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3586702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3587819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood if (match == VOLUMES_ID) { 3588819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood detachVolume(uri); 3589819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood count = 1; 3590819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood } else if (match == MTP_CONNECTED) { 359134be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood synchronized (mMtpServiceConnection) { 359234be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood if (mMtpService != null) { 359334be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood // MTP has disconnected, so release our connection to MtpService 359434be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood getContext().unbindService(mMtpServiceConnection); 359534be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood count = 1; 359634be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood // mMtpServiceConnection.onServiceDisconnected might not get called, 359734be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood // so set mMtpService = null here 359834be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood mMtpService = null; 359934be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood } else { 360034be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood count = 0; 360134be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood } 360234be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood } 3603819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood } else { 3604702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DatabaseHelper database = getDatabaseForUri(uri); 3605702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (database == null) { 3606702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException( 3607819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood "Unknown URI: " + uri + " match: " + match); 3608702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 360910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen database.mNumDeletes++; 3610702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteDatabase db = database.getWritableDatabase(); 3611702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3612702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized (sGetTableAndWhereParam) { 3613702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getTableAndWhere(uri, match, userWhere, sGetTableAndWhereParam); 3614a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen 3615a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen if (sGetTableAndWhereParam.table.equals("files")) { 3616d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen String deleteparam = uri.getQueryParameter(MediaStore.PARAM_DELETE_DATA); 3617d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen if (deleteparam == null || ! deleteparam.equals("false")) { 3618d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen database.mNumQueries++; 3619d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen Cursor c = db.query(sGetTableAndWhereParam.table, 3620d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen sMediaTypeDataId, 3621d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen sGetTableAndWhereParam.where, whereArgs, null, null, null); 3622d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen String [] idvalue = new String[] { "" }; 3623d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen while (c.moveToNext()) { 3624d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen int mediatype = c.getInt(0); 3625d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen if (mediatype == FileColumns.MEDIA_TYPE_IMAGE) { 3626d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen try { 3627d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen Libcore.os.remove(c.getString(1)); 3628d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen idvalue[0] = "" + c.getLong(2); 3629d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen database.mNumQueries++; 3630d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen Cursor cc = db.query("thumbnails", sDataOnlyColumn, 3631d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen "image_id=?", idvalue, null, null, null); 3632d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen while (cc.moveToNext()) { 3633d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen Libcore.os.remove(cc.getString(0)); 3634d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen } 3635d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen cc.close(); 3636d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen database.mNumDeletes++; 3637d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen db.delete("thumbnails", "image_id=?", idvalue); 3638d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen } catch (ErrnoException e) { 3639a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen } 3640d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen } else if (mediatype == FileColumns.MEDIA_TYPE_VIDEO) { 3641d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen try { 3642d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen Libcore.os.remove(c.getString(1)); 3643d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen } catch (ErrnoException e) { 3644d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen } 3645d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen } else if (mediatype == FileColumns.MEDIA_TYPE_AUDIO) { 36465118dba282c95fda77e03e63b6dd11505c474ee5Marco Nelissen idvalue[0] = "" + c.getLong(2); 36475118dba282c95fda77e03e63b6dd11505c474ee5Marco Nelissen db.delete("audio_genres_map", "audio_id=?", idvalue); 36485118dba282c95fda77e03e63b6dd11505c474ee5Marco Nelissen db.delete("audio_playlists_map", "audio_id=?", idvalue); 3649d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen } else if (mediatype == FileColumns.MEDIA_TYPE_PLAYLIST) { 3650d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen // TODO, maybe: remove the audio_playlists_cleanup trigger and implement 3651d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen // it functionality here (clean up the playlist map) 36525afff430a4ebb751dadeb0112a1fe2052c6f5c05Marco Nelissen } 3653a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen } 3654d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen c.close(); 3655a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen } 3656a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen } 3657a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen 3658702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (match) { 365936339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood case MTP_OBJECTS: 3660e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood case MTP_OBJECTS_ID: 3661d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood try { 3662d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood // don't send objectRemoved event since this originated from MTP 3663d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood mDisableMtpObjectCallbacks = true; 366410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen database.mNumDeletes++; 366510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen count = db.delete("files", sGetTableAndWhereParam.where, whereArgs); 3666d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } finally { 3667d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood mDisableMtpObjectCallbacks = false; 3668d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 366936339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood break; 367078b2885edc406273d688536b0eadfea006b20662Marco Nelissen case AUDIO_GENRES_ID_MEMBERS: 367110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen database.mNumDeletes++; 367278b2885edc406273d688536b0eadfea006b20662Marco Nelissen count = db.delete("audio_genres_map", 367378b2885edc406273d688536b0eadfea006b20662Marco Nelissen sGetTableAndWhereParam.where, whereArgs); 367478b2885edc406273d688536b0eadfea006b20662Marco Nelissen break; 3675166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen 3676a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen case IMAGES_THUMBNAILS_ID: 3677a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen case IMAGES_THUMBNAILS: 3678166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen case VIDEO_THUMBNAILS_ID: 3679166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen case VIDEO_THUMBNAILS: 3680166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen // Delete the referenced files first. 3681166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen Cursor c = db.query(sGetTableAndWhereParam.table, 3682166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen sDataOnlyColumn, 3683166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen sGetTableAndWhereParam.where, whereArgs, null, null, null); 3684166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen if (c != null) { 3685166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen while (c.moveToNext()) { 3686166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen try { 3687166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen Libcore.os.remove(c.getString(0)); 3688166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen } catch (ErrnoException e) { 3689166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen } 3690166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen } 3691166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen c.close(); 3692166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen } 3693166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen database.mNumDeletes++; 3694166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen count = db.delete(sGetTableAndWhereParam.table, 3695166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen sGetTableAndWhereParam.where, whereArgs); 3696166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen break; 3697166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen 3698702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project default: 369910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen database.mNumDeletes++; 3700702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count = db.delete(sGetTableAndWhereParam.table, 3701702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sGetTableAndWhereParam.where, whereArgs); 3702702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3703702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 37043631d46b679a64a16918698121916b60d7c86e97Mike Lockwood // Since there are multiple Uris that can refer to the same files 37053631d46b679a64a16918698121916b60d7c86e97Mike Lockwood // and deletes can affect other objects in storage (like subdirectories 37063631d46b679a64a16918698121916b60d7c86e97Mike Lockwood // or playlists) we will notify a change on the entire volume to make 37073631d46b679a64a16918698121916b60d7c86e97Mike Lockwood // sure no listeners miss the notification. 37083631d46b679a64a16918698121916b60d7c86e97Mike Lockwood String volume = uri.getPathSegments().get(0); 37093631d46b679a64a16918698121916b60d7c86e97Mike Lockwood Uri notifyUri = Uri.parse("content://" + MediaStore.AUTHORITY + "/" + volume); 37103631d46b679a64a16918698121916b60d7c86e97Mike Lockwood getContext().getContentResolver().notifyChange(notifyUri, null); 3711702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3712702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3713702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3714702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return count; 3715702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3716702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3717702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 371838b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen public Bundle call(String method, String arg, Bundle extras) { 371938b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen if (MediaStore.UNHIDE_CALL.equals(method)) { 372038b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen processRemovedNoMediaPath(arg); 372138b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen return null; 372238b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen } 372338b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen throw new UnsupportedOperationException("Unsupported call: " + method); 372438b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen } 372538b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen 372638b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen @Override 3727702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public int update(Uri uri, ContentValues initialValues, String userWhere, 3728702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String[] whereArgs) { 3729702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int count; 3730b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // Log.v(TAG, "update for uri="+uri+", initValues="+initialValues); 3731702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int match = URI_MATCHER.match(uri); 373210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen DatabaseHelper helper = getDatabaseForUri(uri); 373310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen if (helper == null) { 3734702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException( 3735702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Unknown URI: " + uri); 3736702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 373710af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumUpdates++; 373810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen 373910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen SQLiteDatabase db = helper.getWritableDatabase(); 3740702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3741b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood String genre = null; 3742b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood if (initialValues != null) { 3743b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood genre = initialValues.getAsString(Audio.AudioColumns.GENRE); 3744b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood initialValues.remove(Audio.AudioColumns.GENRE); 3745b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood } 3746b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood 3747702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized (sGetTableAndWhereParam) { 3748702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getTableAndWhere(uri, match, userWhere, sGetTableAndWhereParam); 3749702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 37501d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood // special case renaming directories via MTP. 37511d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood // in this case we must update all paths in the database with 37521d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood // the directory name as a prefix 37531d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood if ((match == MTP_OBJECTS || match == MTP_OBJECTS_ID) 37541d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood && initialValues != null && initialValues.size() == 1) { 37551d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood String oldPath = null; 3756801ba04ac37ee06dccb8bf4081b29a162795e3a6Mike Lockwood String newPath = initialValues.getAsString(MediaStore.MediaColumns.DATA); 37577f36494e085c26c69cd5925e54028822025eff29Marco Nelissen mDirectoryCache.remove(newPath); 37581d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood // MtpDatabase will rename the directory first, so we test the new file name 375938b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen File f = new File(newPath); 376038b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen if (newPath != null && f.isDirectory()) { 376110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumQueries++; 37621d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood Cursor cursor = db.query(sGetTableAndWhereParam.table, PATH_PROJECTION, 37631d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood userWhere, whereArgs, null, null, null); 37641d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood try { 37651d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood if (cursor != null && cursor.moveToNext()) { 37661d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood oldPath = cursor.getString(1); 37671d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood } 37681d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood } finally { 37691d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood if (cursor != null) cursor.close(); 37701d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood } 37711d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood if (oldPath != null) { 37727f36494e085c26c69cd5925e54028822025eff29Marco Nelissen mDirectoryCache.remove(oldPath); 37731d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood // first rename the row for the directory 377410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumUpdates++; 37751d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood count = db.update(sGetTableAndWhereParam.table, initialValues, 37761d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood sGetTableAndWhereParam.where, whereArgs); 37771d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood if (count > 0) { 37781d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood // then update the paths of any files and folders contained in the directory. 3779dc025ab2edc8d74170ae54dd33860adcca3ad31cMarco Nelissen Object[] bindArgs = new Object[] {oldPath + "/%", oldPath.length() + 1, newPath}; 378010af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumUpdates++; 3781dc025ab2edc8d74170ae54dd33860adcca3ad31cMarco Nelissen db.execSQL("UPDATE files SET _data=?3||SUBSTR(_data, ?2) WHERE _data LIKE ?1;", bindArgs); 37821d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood } 37831d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood 37841d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood if (count > 0 && !db.inTransaction()) { 37851d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood getContext().getContentResolver().notifyChange(uri, null); 37861d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood } 378738b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen if (f.getName().startsWith(".")) { 378838b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen // the new directory name is hidden 378938b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen processNewNoMediaPath(helper, db, newPath); 379038b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen } 37911d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood return count; 37921d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood } 379338b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen } else if (newPath.toLowerCase(Locale.US).endsWith("/.nomedia")) { 379438b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen processNewNoMediaPath(helper, db, newPath); 37951d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood } 37961d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood } 37971d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood 3798702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (match) { 3799702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA: 3800702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID: 3801702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project { 3802702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(initialValues); 38032658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen String albumartist = values.getAsString(MediaStore.Audio.Media.ALBUM_ARTIST); 38042658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen String compilation = values.getAsString(MediaStore.Audio.Media.COMPILATION); 38052658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen values.remove(MediaStore.Audio.Media.COMPILATION); 380607656cccafca173c6ab54c681a69538dcf0516ddMarco Nelissen 3807702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Insert the artist into the artist table and remove it from 3808702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // the input values 3809a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen String artist = values.getAsString("artist"); 38106006570c27674c47fcea8e674832a715cfd653eaMarco Nelissen values.remove("artist"); 3811a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen if (artist != null) { 3812702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long artistRowId; 381310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen HashMap<String, Long> artistCache = helper.mArtistCache; 3814702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized(artistCache) { 3815a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen Long temp = artistCache.get(artist); 3816702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (temp == null) { 381710af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen artistRowId = getKeyIdForName(helper, db, 381810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen "artists", "artist_key", "artist", 3819acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen artist, artist, null, 0, null, artistCache, uri); 3820702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 3821702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project artistRowId = temp.longValue(); 3822702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3823702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3824702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put("artist_id", Integer.toString((int)artistRowId)); 3825702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3826702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 382759948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // Do the same for the album field. 3828a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen String so = values.getAsString("album"); 38296006570c27674c47fcea8e674832a715cfd653eaMarco Nelissen values.remove("album"); 3830702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (so != null) { 3831801ba04ac37ee06dccb8bf4081b29a162795e3a6Mike Lockwood String path = values.getAsString(MediaStore.MediaColumns.DATA); 383259948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen int albumHash = 0; 38332658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen if (albumartist != null) { 38342658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen albumHash = albumartist.hashCode(); 38352658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen } else if (compilation != null && compilation.equals("1")) { 38362658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen // nothing to do, hash already set 383759948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen } else { 38389289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen if (path == null) { 38399289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen if (match == AUDIO_MEDIA) { 38409289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen Log.w(TAG, "Possible multi row album name update without" 38419289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen + " path could give wrong album key"); 38429289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen } else { 38439289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen //Log.w(TAG, "Specify path to avoid extra query"); 38449289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen Cursor c = query(uri, 38459289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen new String[] { MediaStore.Audio.Media.DATA}, 38469289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen null, null, null); 38479289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen if (c != null) { 38489289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen try { 38499289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen int numrows = c.getCount(); 38509289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen if (numrows == 1) { 38519289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen c.moveToFirst(); 38529289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen path = c.getString(0); 38539289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen } else { 38549289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen Log.e(TAG, "" + numrows + " rows for " + uri); 38559289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen } 38569289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen } finally { 38579289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen c.close(); 38589289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen } 38599289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen } 38609289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen } 38619289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen } 38629289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen if (path != null) { 38639289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen albumHash = path.substring(0, path.lastIndexOf('/')).hashCode(); 38649289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen } 386559948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen } 38662658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen 3867702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String s = so.toString(); 3868702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long albumRowId; 386910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen HashMap<String, Long> albumCache = helper.mAlbumCache; 3870702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized(albumCache) { 387159948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen String cacheName = s + albumHash; 387259948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen Long temp = albumCache.get(cacheName); 3873702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (temp == null) { 387410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen albumRowId = getKeyIdForName(helper, db, 387510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen "albums", "album_key", "album", 3876a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen s, cacheName, path, albumHash, artist, albumCache, uri); 3877702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 3878702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project albumRowId = temp.longValue(); 3879702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3880702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3881702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put("album_id", Integer.toString((int)albumRowId)); 3882702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3883702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3884702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // don't allow the title_key field to be updated directly 3885702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.remove("title_key"); 3886702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // If the title field is modified, update the title_key 3887702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project so = values.getAsString("title"); 3888702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (so != null) { 3889702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String s = so.toString(); 3890702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put("title_key", MediaStore.Audio.keyFor(s)); 3891e96c1d9637e89b5f99c7002fd06f7f35a9164849Marco Nelissen // do a final trim of the title, in case it started with the special 3892e96c1d9637e89b5f99c7002fd06f7f35a9164849Marco Nelissen // "sort first" character (ascii \001) 3893e96c1d9637e89b5f99c7002fd06f7f35a9164849Marco Nelissen values.remove("title"); 3894e96c1d9637e89b5f99c7002fd06f7f35a9164849Marco Nelissen values.put("title", s.trim()); 3895702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3896702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 389710af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumUpdates++; 3898afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood count = db.update(sGetTableAndWhereParam.table, values, 3899afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood sGetTableAndWhereParam.where, whereArgs); 3900b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood if (genre != null) { 3901b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood if (count == 1 && match == AUDIO_MEDIA_ID) { 3902b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood long rowId = Long.parseLong(uri.getPathSegments().get(3)); 3903b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood updateGenre(rowId, genre); 3904b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood } else { 3905b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood // can't handle genres for bulk update or for non-audio files 3906b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood Log.w(TAG, "ignoring genre in update: count = " 3907b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood + count + " match = " + match); 3908b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood } 3909b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood } 3910702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3911702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3912702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA: 3913702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA_ID: 3914702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA: 3915702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA_ID: 3916702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project { 3917702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(initialValues); 3918702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Don't allow bucket id or display name to be updated directly. 3919702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // The same names are used for both images and table columns, so 3920702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // we use the ImageColumns constants here. 3921702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.remove(ImageColumns.BUCKET_ID); 3922702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.remove(ImageColumns.BUCKET_DISPLAY_NAME); 3923702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // If the data is being modified update the bucket values 3924702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String data = values.getAsString(MediaColumns.DATA); 3925702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (data != null) { 3926702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project computeBucketValues(data, values); 3927702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3928b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen computeTakenTime(values); 392910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumUpdates++; 3930702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count = db.update(sGetTableAndWhereParam.table, values, 3931702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sGetTableAndWhereParam.where, whereArgs); 393201a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen // if this is a request from MediaScanner, DATA should contains file path 393301a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen // we only process update request from media scanner, otherwise the requests 393401a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen // could be duplicate. 393501a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen if (count > 0 && values.getAsString(MediaStore.MediaColumns.DATA) != null) { 393610af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumQueries++; 393701a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen Cursor c = db.query(sGetTableAndWhereParam.table, 393801a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen READY_FLAG_PROJECTION, sGetTableAndWhereParam.where, 393901a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen whereArgs, null, null, null); 3940b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (c != null) { 3941216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen try { 3942216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen while (c.moveToNext()) { 3943216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen long magic = c.getLong(2); 3944216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen if (magic == 0) { 3945216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen requestMediaThumbnail(c.getString(1), uri, 3946216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen MediaThumbRequest.PRIORITY_NORMAL, 0); 3947216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen } 3948b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 3949216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen } finally { 3950216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen c.close(); 3951b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 3952b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 3953b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 3954702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3955702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3956f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen 3957f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen case AUDIO_PLAYLISTS_ID_MEMBERS_ID: 3958f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen String moveit = uri.getQueryParameter("move"); 3959f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen if (moveit != null) { 3960f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen String key = MediaStore.Audio.Playlists.Members.PLAY_ORDER; 3961f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen if (initialValues.containsKey(key)) { 3962f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen int newpos = initialValues.getAsInteger(key); 3963f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen List <String> segments = uri.getPathSegments(); 3964f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen long playlist = Long.valueOf(segments.get(3)); 3965f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen int oldpos = Integer.valueOf(segments.get(5)); 396610af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen return movePlaylistEntry(helper, db, playlist, oldpos, newpos); 3967f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } 3968f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen throw new IllegalArgumentException("Need to specify " + key + 3969f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " when using 'move' parameter"); 3970f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } 3971f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen // fall through 3972702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project default: 397310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumUpdates++; 3974702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count = db.update(sGetTableAndWhereParam.table, initialValues, 3975702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sGetTableAndWhereParam.where, whereArgs); 3976702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3977702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3978702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3979cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen // in a transaction, the code that began the transaction should be taking 3980cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen // care of notifications once it ends the transaction successfully 3981cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen if (count > 0 && !db.inTransaction()) { 3982702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 3983702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3984702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return count; 3985702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3986702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 398710af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen private int movePlaylistEntry(DatabaseHelper helper, SQLiteDatabase db, 398810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen long playlist, int from, int to) { 3989f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen if (from == to) { 3990f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen return 0; 3991f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } 3992f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen db.beginTransaction(); 3993f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen try { 3994f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen int numlines = 0; 399510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumUpdates += 3; 3996f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen db.execSQL("UPDATE audio_playlists_map SET play_order=-1" + 3997f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " WHERE play_order=" + from + 3998f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " AND playlist_id=" + playlist); 3999f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen // We could just run both of the next two statements, but only one of 4000f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen // of them will actually do anything, so might as well skip the compile 4001f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen // and execute steps. 4002f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen if (from < to) { 4003f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen db.execSQL("UPDATE audio_playlists_map SET play_order=play_order-1" + 4004f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " WHERE play_order<=" + to + " AND play_order>" + from + 4005f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " AND playlist_id=" + playlist); 4006f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen numlines = to - from + 1; 4007f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } else { 4008f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen db.execSQL("UPDATE audio_playlists_map SET play_order=play_order+1" + 4009f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " WHERE play_order>=" + to + " AND play_order<" + from + 4010f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " AND playlist_id=" + playlist); 4011f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen numlines = from - to + 1; 4012f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } 4013f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen db.execSQL("UPDATE audio_playlists_map SET play_order=" + to + 4014f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " WHERE play_order=-1 AND playlist_id=" + playlist); 4015f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen db.setTransactionSuccessful(); 4016f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen Uri uri = MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI 4017f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen .buildUpon().appendEncodedPath(String.valueOf(playlist)).build(); 4018f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen getContext().getContentResolver().notifyChange(uri, null); 4019f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen return numlines; 4020f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } finally { 4021f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen db.endTransaction(); 4022f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } 4023f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } 4024f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen 4025702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final String[] openFileColumns = new String[] { 4026702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.MediaColumns.DATA, 4027702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project }; 4028702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4029702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 4030702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public ParcelFileDescriptor openFile(Uri uri, String mode) 4031702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throws FileNotFoundException { 403271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen 4033702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ParcelFileDescriptor pfd = null; 403471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen 403571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (URI_MATCHER.match(uri) == AUDIO_ALBUMART_FILE_ID) { 403671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // get album art for the specified media file 403771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen DatabaseHelper database = getDatabaseForUri(uri); 403871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (database == null) { 403971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen throw new IllegalStateException("Couldn't open database for " + uri); 404071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 404171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen SQLiteDatabase db = database.getReadableDatabase(); 40425fde670987a55d69442566dcbdb7830d5f1587c6Chih-Chung Chang if (db == null) { 40435fde670987a55d69442566dcbdb7830d5f1587c6Chih-Chung Chang throw new IllegalStateException("Couldn't open database for " + uri); 40445fde670987a55d69442566dcbdb7830d5f1587c6Chih-Chung Chang } 404571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 404671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen int songid = Integer.parseInt(uri.getPathSegments().get(3)); 404771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen qb.setTables("audio_meta"); 404871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen qb.appendWhere("_id=" + songid); 404971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen Cursor c = qb.query(db, 405071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen new String [] { 405171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen MediaStore.Audio.Media.DATA, 405271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen MediaStore.Audio.Media.ALBUM_ID }, 405371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen null, null, null, null, null); 405471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (c.moveToFirst()) { 405571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen String audiopath = c.getString(0); 405671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen int albumid = c.getInt(1); 405771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // Try to get existing album art for this album first, which 405871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // could possibly have been obtained from a different file. 405971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // If that fails, try to get it from this specific file. 406071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen Uri newUri = ContentUris.withAppendedId(ALBUMART_URI, albumid); 406171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen try { 40623fa7593ce394cdaad4a3db622d415fd8497f4a9dMarco Nelissen pfd = openFileHelper(newUri, mode); 406371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } catch (FileNotFoundException ex) { 406471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // That didn't work, now try to get it from the specific file 406571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen pfd = getThumb(db, audiopath, albumid, null); 406671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 406771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 406871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen c.close(); 406971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen return pfd; 407071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 407171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen 4072702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 4073702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project pfd = openFileHelper(uri, mode); 4074702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } catch (FileNotFoundException ex) { 407571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (mode.contains("w")) { 407671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // if the file couldn't be created, we shouldn't extract album art 407771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen throw ex; 407871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 407971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen 4080702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (URI_MATCHER.match(uri) == AUDIO_ALBUMART_ID) { 4081702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Tried to open an album art file which does not exist. Regenerate. 4082702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DatabaseHelper database = getDatabaseForUri(uri); 4083702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (database == null) { 4084702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw ex; 4085702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4086702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteDatabase db = database.getReadableDatabase(); 40875fde670987a55d69442566dcbdb7830d5f1587c6Chih-Chung Chang if (db == null) { 40885fde670987a55d69442566dcbdb7830d5f1587c6Chih-Chung Chang throw new IllegalStateException("Couldn't open database for " + uri); 40895fde670987a55d69442566dcbdb7830d5f1587c6Chih-Chung Chang } 4090702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 4091702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int albumid = Integer.parseInt(uri.getPathSegments().get(3)); 409271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen qb.setTables("audio_meta"); 4093702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("album_id=" + albumid); 4094702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Cursor c = qb.query(db, 4095702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project new String [] { 4096702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.Audio.Media.DATA }, 4097a4d7f8a140c9a66bfcb28c5197521db6d62e13beMarco Nelissen null, null, null, null, MediaStore.Audio.Media.TRACK); 409871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (c.moveToFirst()) { 4099702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String audiopath = c.getString(0); 410071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen pfd = getThumb(db, audiopath, albumid, uri); 4101702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4102702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project c.close(); 4103702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 410471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (pfd == null) { 410571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen throw ex; 410671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 4107702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4108702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return pfd; 4109702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4110702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4111702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private class ThumbData { 411210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen DatabaseHelper helper; 4113702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteDatabase db; 4114702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String path; 4115702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long album_id; 4116702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Uri albumart_uri; 4117702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4118702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 411910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen private void makeThumbAsync(DatabaseHelper helper, SQLiteDatabase db, 412010af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen String path, long album_id) { 41218a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber synchronized (mPendingThumbs) { 41228a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (mPendingThumbs.contains(path)) { 41238a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // There's already a request to make an album art thumbnail 41248a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // for this audio file in the queue. 41258a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber return; 41268a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 41278a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 41288a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber mPendingThumbs.add(path); 41298a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 41308a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 4131702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ThumbData d = new ThumbData(); 413210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen d.helper = helper; 4133702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project d.db = db; 4134702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project d.path = path; 4135702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project d.album_id = album_id; 4136a9c4e330dacb37cfffa9c00f7da83cafde4accefMarco Nelissen d.albumart_uri = ContentUris.withAppendedId(mAlbumArtBaseUri, album_id); 41378a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 41388a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // Instead of processing thumbnail requests in the order they were 41398a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // received we instead process them stack-based, i.e. LIFO. 41408a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // The idea behind this is that the most recently requested thumbnails 41418a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // are most likely the ones still in the user's view, whereas those 41428a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // requested earlier may have already scrolled off. 41438a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber synchronized (mThumbRequestStack) { 41448a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber mThumbRequestStack.push(d); 41458a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 41468a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 41478a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // Trigger the handler. 4148b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen Message msg = mThumbHandler.obtainMessage(ALBUM_THUMB); 4149702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project msg.sendToTarget(); 4150702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4151702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 41528a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // Extract compressed image data from the audio file itself or, if that fails, 41538a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // look for a file "AlbumArt.jpg" in the containing directory. 41548a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber private static byte[] getCompressedAlbumArt(Context context, String path) { 41558a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber byte[] compressed = null; 4156702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4157702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 4158702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File f = new File(path); 4159702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ParcelFileDescriptor pfd = ParcelFileDescriptor.open(f, 4160702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ParcelFileDescriptor.MODE_READ_ONLY); 4161702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 41628a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber MediaScanner scanner = new MediaScanner(context); 41638a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber compressed = scanner.extractAlbumArt(pfd.getFileDescriptor()); 4164702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project pfd.close(); 4165702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4166d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // If no embedded art exists, look for a suitable image file in the 41673f9c37ea95a3bdf5f84dc79eb199256c4deda29aMarco Nelissen // same directory as the media file, except if that directory is 41683f9c37ea95a3bdf5f84dc79eb199256c4deda29aMarco Nelissen // is the root directory of the sd card or the download directory. 4169d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // We look for, in order of preference: 4170d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // 0 AlbumArt.jpg 4171d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // 1 AlbumArt*Large.jpg 4172d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // 2 Any other jpg image with 'albumart' anywhere in the name 4173d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // 3 Any other jpg image 4174d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // 4 any other png image 41758a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (compressed == null && path != null) { 4176702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int lastSlash = path.lastIndexOf('/'); 4177702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (lastSlash > 0) { 4178d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen 41793f9c37ea95a3bdf5f84dc79eb199256c4deda29aMarco Nelissen String artPath = path.substring(0, lastSlash); 41809be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood String sdroot = mExternalStoragePaths[0]; 41810fe3097230b324e65a874bd7c8c0f430d2fb8cbeMarco Nelissen String dwndir = Environment.getExternalStoragePublicDirectory( 41822f07f572bc574b685b491ee07a6209c7f2dcb13fMarco Nelissen Environment.DIRECTORY_DOWNLOADS).getAbsolutePath(); 4183d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen 4184d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen String bestmatch = null; 4185d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen synchronized (sFolderArtMap) { 4186d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen if (sFolderArtMap.containsKey(artPath)) { 4187d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = sFolderArtMap.get(artPath); 4188ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen } else if (!artPath.equalsIgnoreCase(sdroot) && 4189ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen !artPath.equalsIgnoreCase(dwndir)) { 4190d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen File dir = new File(artPath); 4191d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen String [] entrynames = dir.list(); 4192d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen if (entrynames == null) { 4193d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen return null; 4194d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } 4195d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = null; 4196d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen int matchlevel = 1000; 4197d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen for (int i = entrynames.length - 1; i >=0; i--) { 4198d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen String entry = entrynames[i].toLowerCase(); 4199d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen if (entry.equals("albumart.jpg")) { 4200d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = entrynames[i]; 4201d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen break; 4202d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } else if (entry.startsWith("albumart") 4203d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen && entry.endsWith("large.jpg") 4204d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen && matchlevel > 1) { 4205d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = entrynames[i]; 4206d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen matchlevel = 1; 4207d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } else if (entry.contains("albumart") 4208d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen && entry.endsWith(".jpg") 4209d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen && matchlevel > 2) { 4210d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = entrynames[i]; 4211d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen matchlevel = 2; 4212d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } else if (entry.endsWith(".jpg") && matchlevel > 3) { 4213d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = entrynames[i]; 4214d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen matchlevel = 3; 4215d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } else if (entry.endsWith(".png") && matchlevel > 4) { 4216d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = entrynames[i]; 4217d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen matchlevel = 4; 4218d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } 4219d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } 4220d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // note that this may insert null if no album art was found 4221d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen sFolderArtMap.put(artPath, bestmatch); 4222d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } 4223d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } 4224d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen 4225d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen if (bestmatch != null) { 42263f9c37ea95a3bdf5f84dc79eb199256c4deda29aMarco Nelissen File file = new File(artPath, bestmatch); 4227d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen if (file.exists()) { 4228d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen compressed = new byte[(int)file.length()]; 4229d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen FileInputStream stream = null; 4230d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen try { 4231d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen stream = new FileInputStream(file); 4232d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen stream.read(compressed); 4233d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } catch (IOException ex) { 4234d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen compressed = null; 4235d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } finally { 4236d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen if (stream != null) { 4237d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen stream.close(); 4238d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } 4239702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4240702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4241702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4242702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4243702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 42448a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } catch (IOException e) { 42458a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 4246702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 42478a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber return compressed; 42488a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 4249702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 42508a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // Return a URI to write the album art to and update the database as necessary. 425110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen Uri getAlbumArtOutputUri(DatabaseHelper helper, SQLiteDatabase db, long album_id, Uri albumart_uri) { 42528a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber Uri out = null; 42538a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // TODO: this could be done more efficiently with a call to db.replace(), which 42548a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // replaces or inserts as needed, making it unnecessary to query() first. 42558a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (albumart_uri != null) { 4256801ba04ac37ee06dccb8bf4081b29a162795e3a6Mike Lockwood Cursor c = query(albumart_uri, new String [] { MediaStore.MediaColumns.DATA }, 42578a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber null, null, null); 4258d8c100241c1c8983deeae6329111e2bce997294dJoakim Johansson try { 4259d8c100241c1c8983deeae6329111e2bce997294dJoakim Johansson if (c != null && c.moveToFirst()) { 4260d8c100241c1c8983deeae6329111e2bce997294dJoakim Johansson String albumart_path = c.getString(0); 4261d8c100241c1c8983deeae6329111e2bce997294dJoakim Johansson if (ensureFileExists(albumart_path)) { 4262d8c100241c1c8983deeae6329111e2bce997294dJoakim Johansson out = albumart_uri; 4263d8c100241c1c8983deeae6329111e2bce997294dJoakim Johansson } 4264d8c100241c1c8983deeae6329111e2bce997294dJoakim Johansson } else { 4265d8c100241c1c8983deeae6329111e2bce997294dJoakim Johansson albumart_uri = null; 4266d8c100241c1c8983deeae6329111e2bce997294dJoakim Johansson } 4267d8c100241c1c8983deeae6329111e2bce997294dJoakim Johansson } finally { 4268d8c100241c1c8983deeae6329111e2bce997294dJoakim Johansson if (c != null) { 4269d8c100241c1c8983deeae6329111e2bce997294dJoakim Johansson c.close(); 4270702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4271702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 427271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 427371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (albumart_uri == null){ 42748a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber ContentValues initialValues = new ContentValues(); 42758a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber initialValues.put("album_id", album_id); 42768a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber try { 42778a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber ContentValues values = ensureFile(false, initialValues, "", ALBUM_THUMB_FOLDER); 427810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumInserts++; 4279801ba04ac37ee06dccb8bf4081b29a162795e3a6Mike Lockwood long rowId = db.insert("album_art", MediaStore.MediaColumns.DATA, values); 42808a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (rowId > 0) { 42818a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber out = ContentUris.withAppendedId(ALBUMART_URI, rowId); 4282702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 42838a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } catch (IllegalStateException ex) { 42848a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber Log.e(TAG, "error creating album thumb file"); 42858a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 42868a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 42878a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber return out; 42888a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 42898a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 42908a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // Write out the album art to the output URI, recompresses the given Bitmap 42918a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // if necessary, otherwise writes the compressed data. 42928a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber private void writeAlbumArt( 42938a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber boolean need_to_recompress, Uri out, byte[] compressed, Bitmap bm) { 42948a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber boolean success = false; 42958a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber try { 42968a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber OutputStream outstream = getContext().getContentResolver().openOutputStream(out); 42978a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 42988a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (!need_to_recompress) { 42998a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // No need to recompress here, just write out the original 43008a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // compressed data here. 43018a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber outstream.write(compressed); 43028a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber success = true; 43038a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } else { 430470676508bd3a081edd909875e141f2c48d79c1acDaniel Lehmann success = bm.compress(Bitmap.CompressFormat.JPEG, 85, outstream); 4305702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 43068a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 43078a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber outstream.close(); 43088a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } catch (FileNotFoundException ex) { 43098a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber Log.e(TAG, "error creating file", ex); 4310702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } catch (IOException ex) { 43118a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber Log.e(TAG, "error creating file", ex); 43128a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 43138a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (!success) { 43148a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // the thumbnail was not written successfully, delete the entry that refers to it 43158a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber getContext().getContentResolver().delete(out, null, null); 4316702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 43178a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 43188a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 431971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen private ParcelFileDescriptor getThumb(SQLiteDatabase db, String path, long album_id, 432071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen Uri albumart_uri) { 432171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen ThumbData d = new ThumbData(); 432271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen d.db = db; 432371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen d.path = path; 432471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen d.album_id = album_id; 432571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen d.albumart_uri = albumart_uri; 432671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen return makeThumbInternal(d); 432771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 432871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen 432971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen private ParcelFileDescriptor makeThumbInternal(ThumbData d) { 43308a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber byte[] compressed = getCompressedAlbumArt(getContext(), d.path); 4331702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 43328a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (compressed == null) { 433371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen return null; 43348a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 43358a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 43368a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber Bitmap bm = null; 43378a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber boolean need_to_recompress = true; 43388a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 43398a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber try { 43408a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // get the size of the bitmap 43418a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber BitmapFactory.Options opts = new BitmapFactory.Options(); 43428a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.inJustDecodeBounds = true; 43438a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.inSampleSize = 1; 43448a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber BitmapFactory.decodeByteArray(compressed, 0, compressed.length, opts); 43458a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 43468a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // request a reasonably sized output image 434770676508bd3a081edd909875e141f2c48d79c1acDaniel Lehmann final Resources r = getContext().getResources(); 434870676508bd3a081edd909875e141f2c48d79c1acDaniel Lehmann final int maximumThumbSize = r.getDimensionPixelSize(R.dimen.maximum_thumb_size); 434970676508bd3a081edd909875e141f2c48d79c1acDaniel Lehmann while (opts.outHeight > maximumThumbSize || opts.outWidth > maximumThumbSize) { 43508a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.outHeight /= 2; 43518a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.outWidth /= 2; 43528a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.inSampleSize *= 2; 43538a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 43548a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 43558a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (opts.inSampleSize == 1) { 43568a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // The original album art was of proper size, we won't have to 43578a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // recompress the bitmap later. 43588a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber need_to_recompress = false; 43598a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } else { 43608a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // get the image for real now 43618a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.inJustDecodeBounds = false; 43628a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.inPreferredConfig = Bitmap.Config.RGB_565; 43638a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber bm = BitmapFactory.decodeByteArray(compressed, 0, compressed.length, opts); 43648a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 43658a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (bm != null && bm.getConfig() == null) { 4366a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen Bitmap nbm = bm.copy(Bitmap.Config.RGB_565, false); 4367a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen if (nbm != null && nbm != bm) { 4368a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen bm.recycle(); 4369a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen bm = nbm; 4370a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen } 43718a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 43728a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 43738a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } catch (Exception e) { 43748a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 43758a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 43768a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (need_to_recompress && bm == null) { 437771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen return null; 43788a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 43798a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 438071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (d.albumart_uri == null) { 438171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // this one doesn't need to be saved (probably a song with an unknown album), 438271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // so stick it in a memory file and return that 438371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen try { 438424001394f571b1f0378840cbf299288e4df10508Bjorn Bringert return ParcelFileDescriptor.fromData(compressed, "albumthumb"); 438571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } catch (IOException e) { 438671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 438771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } else { 4388a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen // This one needs to actually be saved on the sd card. 4389a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen // This is wrapped in a transaction because there are various things 4390a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen // that could go wrong while generating the thumbnail, and we only want 4391a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen // to update the database when all steps succeeded. 4392a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen d.db.beginTransaction(); 4393a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen try { 439410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen Uri out = getAlbumArtOutputUri(d.helper, d.db, d.album_id, d.albumart_uri); 4395a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen 4396a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen if (out != null) { 4397a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen writeAlbumArt(need_to_recompress, out, compressed, bm); 4398a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen getContext().getContentResolver().notifyChange(MEDIA_URI, null); 4399a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen ParcelFileDescriptor pfd = openFileHelper(out, "r"); 4400a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen d.db.setTransactionSuccessful(); 4401a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen return pfd; 4402a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen } 4403a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen } catch (FileNotFoundException ex) { 4404a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen // do nothing, just return null below 4405a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen } catch (UnsupportedOperationException ex) { 4406a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen // do nothing, just return null below 4407a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen } finally { 4408a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen d.db.endTransaction(); 4409a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen if (bm != null) { 4410a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen bm.recycle(); 441171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 441271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 44138a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 441471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen return null; 4415702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4416702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4417702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 4418702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Look up the artist or album entry for the given name, creating that entry 4419702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * if it does not already exists. 4420702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param db The database 4421702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param table The table to store the key/name pair in. 4422702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param keyField The name of the key-column 4423702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param nameField The name of the name-column 4424702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param rawName The name that the calling app was trying to insert into the database 442559948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen * @param cacheName The string that will be inserted in to the cache 442659948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen * @param path The full path to the file being inserted in to the audio table 442759948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen * @param albumHash A hash to distinguish between different albums of the same name 4428a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen * @param artist The name of the artist, if known 4429702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param cache The cache to add this entry to 4430702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param srcuri The Uri that prompted the call to this method, used for determining whether this is 4431702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * the internal or external database 4432702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @return The row ID for this artist/album, or -1 if the provided name was invalid 4433702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 443410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen private long getKeyIdForName(DatabaseHelper helper, SQLiteDatabase db, 443510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen String table, String keyField, String nameField, 443659948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen String rawName, String cacheName, String path, int albumHash, 4437a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen String artist, HashMap<String, Long> cache, Uri srcuri) { 4438702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long rowId; 4439702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4440702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rawName == null || rawName.length() == 0) { 444151cba5e1acf1c56be3dc6c7c46a73a5a0409b452Marco Nelissen rawName = MediaStore.UNKNOWN_STRING; 4442702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4443702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String k = MediaStore.Audio.keyFor(rawName); 4444702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4445702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (k == null) { 444651cba5e1acf1c56be3dc6c7c46a73a5a0409b452Marco Nelissen // shouldn't happen, since we only get null keys for null inputs 444751cba5e1acf1c56be3dc6c7c46a73a5a0409b452Marco Nelissen Log.e(TAG, "null key", new Exception()); 4448702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return -1; 4449702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4450702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 445159948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen boolean isAlbum = table.equals("albums"); 4452e31cfb1a2c21e7ac7a646d40afbb48f49fab6907Marco Nelissen boolean isUnknown = MediaStore.UNKNOWN_STRING.equals(rawName); 445359948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen 44542658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen // To distinguish same-named albums, we append a hash. The hash is based 44552658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen // on the "album artist" tag if present, otherwise on the "compilation" tag 44562658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen // if present, otherwise on the path. 445759948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // Ideally we would also take things like CDDB ID in to account, so 445859948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // we can group files from the same album that aren't in the same 445959948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // folder, but this is a quick and easy start that works immediately 446059948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // without requiring support from the mp3, mp4 and Ogg meta data 446159948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // readers, as long as the albums are in different folders. 4462a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen if (isAlbum) { 446359948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen k = k + albumHash; 4464a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen if (isUnknown) { 4465a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen k = k + artist; 4466a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen } 446759948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen } 446859948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen 4469702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String [] selargs = { k }; 447010af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumQueries++; 4471702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Cursor c = db.query(table, null, keyField + "=?", selargs, null, null, null); 4472702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4473702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 4474702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (c.getCount()) { 4475702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case 0: { 4476702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // insert new entry into table 4477702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues otherValues = new ContentValues(); 4478702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project otherValues.put(keyField, k); 4479702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project otherValues.put(nameField, rawName); 448010af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumInserts++; 4481702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert(table, "duration", otherValues); 448259948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen if (path != null && isAlbum && ! isUnknown) { 4483702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // We just inserted a new album. Now create an album art thumbnail for it. 448410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen makeThumbAsync(helper, db, path, rowId); 4485702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4486702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 4487702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String volume = srcuri.toString().substring(16, 24); // extract internal/external 4488702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Uri uri = Uri.parse("content://media/" + volume + "/audio/" + table + "/" + rowId); 4489702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 4490702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4491702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4492702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 4493702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case 1: { 4494702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Use the existing entry 4495702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project c.moveToFirst(); 4496702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = c.getLong(0); 4497702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4498702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Determine whether the current rawName is better than what's 4499702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // currently stored in the table, and update the table if it is. 4500702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String currentFancyName = c.getString(2); 4501702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String bestName = makeBestName(rawName, currentFancyName); 4502702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!bestName.equals(currentFancyName)) { 4503702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // update the table with the new name 4504702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues newValues = new ContentValues(); 4505702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newValues.put(nameField, bestName); 450610af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumUpdates++; 4507702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.update(table, newValues, "rowid="+Integer.toString((int)rowId), null); 4508702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String volume = srcuri.toString().substring(16, 24); // extract internal/external 4509702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Uri uri = Uri.parse("content://media/" + volume + "/audio/" + table + "/" + rowId); 4510702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 4511702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4512702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4513702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 4514702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project default: 4515702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // corrupt database 4516702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Log.e(TAG, "Multiple entries in table " + table + " for key " + k); 4517702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = -1; 4518702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 4519702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4520702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 4521702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (c != null) c.close(); 4522702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4523702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 452459948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen if (cache != null && ! isUnknown) { 452559948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen cache.put(cacheName, rowId); 4526702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4527702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return rowId; 4528702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4529702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4530702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 4531702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Returns the best string to use for display, given two names. 4532702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Note that this function does not necessarily return either one 4533702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * of the provided names; it may decide to return a better alternative 4534702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * (for example, specifying the inputs "Police" and "Police, The" will 4535702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * return "The Police") 4536702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 4537702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * The basic assumptions are: 4538702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * - longer is better ("The police" is better than "Police") 4539702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * - prefix is better ("The Police" is better than "Police, The") 4540702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * - accents are better ("Motörhead" is better than "Motorhead") 4541702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 4542702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param one The first of the two names to consider 4543702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param two The last of the two names to consider 4544702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @return The actual name to use 4545702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 4546702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String makeBestName(String one, String two) { 4547702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String name; 4548702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4549702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Longer names are usually better. 4550702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (one.length() > two.length()) { 4551702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project name = one; 4552702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 4553702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Names with accents are usually better, and conveniently sort later 4554702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (one.toLowerCase().compareTo(two.toLowerCase()) > 0) { 4555702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project name = one; 4556702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 4557702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project name = two; 4558702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4559702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4560702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4561702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Prefixes are better than postfixes. 4562702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (name.endsWith(", the") || name.endsWith(",the") || 4563702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project name.endsWith(", an") || name.endsWith(",an") || 4564702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project name.endsWith(", a") || name.endsWith(",a")) { 4565702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String fix = name.substring(1 + name.lastIndexOf(',')); 4566702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project name = fix.trim() + " " + name.substring(0, name.lastIndexOf(',')); 4567702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4568702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4569702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // TODO: word-capitalize the resulting name 4570702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return name; 4571702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4572702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4573702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4574702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 4575702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Looks up the database based on the given URI. 4576702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 4577702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param uri The requested URI 4578702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @returns the database for the given URI 4579702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 4580702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private DatabaseHelper getDatabaseForUri(Uri uri) { 4581702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized (mDatabases) { 4582702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (uri.getPathSegments().size() > 1) { 4583702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return mDatabases.get(uri.getPathSegments().get(0)); 4584702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4585702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4586702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return null; 4587702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4588702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4589fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn static boolean isMediaDatabaseName(String name) { 4590fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn if (INTERNAL_DATABASE_NAME.equals(name)) { 4591fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn return true; 4592fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn } 4593fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn if (EXTERNAL_DATABASE_NAME.equals(name)) { 4594fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn return true; 4595fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn } 4596fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn if (name.startsWith("external-")) { 4597fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn return true; 4598fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn } 4599fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn return false; 4600fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn } 4601fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn 4602fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn static boolean isInternalMediaDatabaseName(String name) { 4603fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn if (INTERNAL_DATABASE_NAME.equals(name)) { 4604fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn return true; 4605fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn } 4606fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn return false; 4607fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn } 4608fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn 4609702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 4610702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Attach the database for a volume (internal or external). 4611702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Does nothing if the volume is already attached, otherwise 4612702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * checks the volume ID and sets up the corresponding database. 4613702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 4614702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param volume to attach, either {@link #INTERNAL_VOLUME} or {@link #EXTERNAL_VOLUME}. 4615702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @return the content URI of the attached volume. 4616702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 4617702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private Uri attachVolume(String volume) { 461875392afde5217038b0c98077758bb9329c2431b2Jeff Brown if (Binder.getCallingPid() != Process.myPid()) { 4619702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new SecurityException( 4620702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Opening and closing databases not allowed."); 4621702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4622702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4623702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized (mDatabases) { 4624702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (mDatabases.get(volume) != null) { // Already attached 4625702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Uri.parse("content://media/" + volume); 4626702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4627702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4628993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood Context context = getContext(); 462910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen DatabaseHelper helper; 4630702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (INTERNAL_VOLUME.equals(volume)) { 463110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper = new DatabaseHelper(context, INTERNAL_DATABASE_NAME, true, 4632fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn false, mObjectRemovedCallback); 4633702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else if (EXTERNAL_VOLUME.equals(volume)) { 4634993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood if (Environment.isExternalStorageRemovable()) { 46359be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood String path = mExternalStoragePaths[0]; 4636993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood int volumeID = FileUtils.getFatVolumeId(path); 4637993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood if (LOCAL_LOGV) Log.v(TAG, path + " volume ID: " + volumeID); 4638993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood 4639993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood // generate database name based on volume ID 4640993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood String dbName = "external-" + Integer.toHexString(volumeID) + ".db"; 464110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper = new DatabaseHelper(context, dbName, false, 4642fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn false, mObjectRemovedCallback); 4643993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood mVolumeId = volumeID; 4644993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood } else { 4645993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood // external database name should be EXTERNAL_DATABASE_NAME 4646993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood // however earlier releases used the external-XXXXXXXX.db naming 4647993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood // for devices without removable storage, and in that case we need to convert 4648993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood // to this new convention 4649993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood File dbFile = context.getDatabasePath(EXTERNAL_DATABASE_NAME); 4650993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood if (!dbFile.exists()) { 4651993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood // find the most recent external database and rename it to 4652993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood // EXTERNAL_DATABASE_NAME, and delete any other older 4653993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood // external database files 4654993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood File recentDbFile = null; 4655993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood for (String database : context.databaseList()) { 4656993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood if (database.startsWith("external-")) { 4657993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood File file = context.getDatabasePath(database); 4658993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood if (recentDbFile == null) { 4659993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood recentDbFile = file; 4660993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood } else if (file.lastModified() > recentDbFile.lastModified()) { 4661993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood recentDbFile.delete(); 4662993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood recentDbFile = file; 4663993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood } else { 4664993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood file.delete(); 4665993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood } 4666993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood } 4667993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood } 4668993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood if (recentDbFile != null) { 4669993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood if (recentDbFile.renameTo(dbFile)) { 4670993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood Log.d(TAG, "renamed database " + recentDbFile.getName() + 4671993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood " to " + EXTERNAL_DATABASE_NAME); 4672993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood } else { 4673993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood Log.e(TAG, "Failed to rename database " + recentDbFile.getName() + 4674993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood " to " + EXTERNAL_DATABASE_NAME); 4675993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood // This shouldn't happen, but if it does, continue using 4676993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood // the file under its old name 4677993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood dbFile = recentDbFile; 4678993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood } 4679993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood } 4680993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood // else DatabaseHelper will create one named EXTERNAL_DATABASE_NAME 4681993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood } 468210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper = new DatabaseHelper(context, dbFile.getName(), false, 4683fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn false, mObjectRemovedCallback); 4684993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood } 4685702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 4686702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalArgumentException("There is no volume named " + volume); 4687702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4688702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 468910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen mDatabases.put(volume, helper); 4690702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 469110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen if (!helper.mInternal) { 4692ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood // create default directories (only happens on first boot) 469310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen createDefaultFolders(helper, helper.getWritableDatabase()); 4694ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood 4695702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // clean up stray album art files: delete every file not in the database 46969be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood File[] files = new File(mExternalStoragePaths[0], ALBUM_THUMB_FOLDER).listFiles(); 4697702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project HashSet<String> fileSet = new HashSet(); 4698702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project for (int i = 0; files != null && i < files.length; i++) { 4699702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project fileSet.add(files[i].getPath()); 4700702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4701702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4702702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Cursor cursor = query(MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI, 4703702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project new String[] { MediaStore.Audio.Albums.ALBUM_ART }, null, null, null); 4704702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 4705702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project while (cursor != null && cursor.moveToNext()) { 4706702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project fileSet.remove(cursor.getString(0)); 4707702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4708702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 4709702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (cursor != null) cursor.close(); 4710702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4711702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4712702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Iterator<String> iterator = fileSet.iterator(); 4713702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project while (iterator.hasNext()) { 4714702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String filename = iterator.next(); 4715702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (LOCAL_LOGV) Log.v(TAG, "deleting obsolete album art " + filename); 4716702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project new File(filename).delete(); 4717702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4718702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4719702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4720702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4721702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (LOCAL_LOGV) Log.v(TAG, "Attached volume: " + volume); 4722702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Uri.parse("content://media/" + volume); 4723702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4724702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4725702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 4726702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Detach the database for a volume (must be external). 4727702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Does nothing if the volume is already detached, otherwise 4728702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * closes the database and sends a notification to listeners. 4729702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 4730702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param uri The content URI of the volume, as returned by {@link #attachVolume} 4731702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 4732702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private void detachVolume(Uri uri) { 473375392afde5217038b0c98077758bb9329c2431b2Jeff Brown if (Binder.getCallingPid() != Process.myPid()) { 4734702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new SecurityException( 4735702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Opening and closing databases not allowed."); 4736702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4737702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4738702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String volume = uri.getPathSegments().get(0); 4739702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (INTERNAL_VOLUME.equals(volume)) { 4740702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException( 4741702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Deleting the internal volume is not allowed"); 4742702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else if (!EXTERNAL_VOLUME.equals(volume)) { 4743702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalArgumentException( 4744702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "There is no volume named " + volume); 4745702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4746702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4747702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized (mDatabases) { 4748702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DatabaseHelper database = mDatabases.get(volume); 4749702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (database == null) return; 4750702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4751702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 4752702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // touch the database file to show it is most recently used 4753702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File file = new File(database.getReadableDatabase().getPath()); 4754702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project file.setLastModified(System.currentTimeMillis()); 4755e9ee0248d62f3badef8a554f35f78e9116ef8a5cMike Lockwood } catch (Exception e) { 4756702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Log.e(TAG, "Can't touch database file", e); 4757702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4758702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4759702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mDatabases.remove(volume); 4760702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project database.close(); 4761702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4762702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4763702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 4764702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (LOCAL_LOGV) Log.v(TAG, "Detached volume: " + volume); 4765702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4766702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4767702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static String TAG = "MediaProvider"; 4768ae62a1d602e7ed2e0e30e271bddbb27aa71469f6Christian Mehlmauer private static final boolean LOCAL_LOGV = false; 4769971a2ef5165e2072c76bf25049fdda94187019c2Dianne Hackborn 4770702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final String INTERNAL_DATABASE_NAME = "internal.db"; 4771993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood private static final String EXTERNAL_DATABASE_NAME = "external.db"; 4772702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4773702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // maximum number of cached external databases to keep 4774702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int MAX_EXTERNAL_DATABASES = 3; 4775702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4776702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Delete databases that have not been used in two months 4777702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // 60 days in milliseconds (1000 * 60 * 60 * 24 * 60) 4778702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final long OBSOLETE_DATABASE_DB = 5184000000L; 4779702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4780702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private HashMap<String, DatabaseHelper> mDatabases; 4781702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4782702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private Handler mThumbHandler; 4783702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4784702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // name of the volume currently being scanned by the media scanner (or null) 4785702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private String mMediaScannerVolume; 4786702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 47870027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen // current FAT volume ID 4788993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood private int mVolumeId = -1; 47890027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen 4790702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project static final String INTERNAL_VOLUME = "internal"; 4791702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project static final String EXTERNAL_VOLUME = "external"; 4792268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen static final String ALBUM_THUMB_FOLDER = "Android/data/com.android.providers.media/albumthumbs"; 4793702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4794702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // path for writing contents of in memory temp database 4795702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private String mTempDatabasePath; 4796702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 47971717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood // WARNING: the values of IMAGES_MEDIA, AUDIO_MEDIA, and VIDEO_MEDIA and AUDIO_PLAYLISTS 479816dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood // are stored in the "files" table, so do not renumber them unless you also add 47991717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood // a corresponding database upgrade step for it. 4800702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int IMAGES_MEDIA = 1; 4801702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int IMAGES_MEDIA_ID = 2; 4802702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int IMAGES_THUMBNAILS = 3; 4803702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int IMAGES_THUMBNAILS_ID = 4; 4804702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4805702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_MEDIA = 100; 4806702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_MEDIA_ID = 101; 4807702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_MEDIA_ID_GENRES = 102; 4808702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_MEDIA_ID_GENRES_ID = 103; 4809702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_MEDIA_ID_PLAYLISTS = 104; 4810702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_MEDIA_ID_PLAYLISTS_ID = 105; 4811702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_GENRES = 106; 4812702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_GENRES_ID = 107; 4813702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_GENRES_ID_MEMBERS = 108; 4814bfbc30ff3b9e3a96b08c525d0971d8d8543ab000Marco Nelissen private static final int AUDIO_GENRES_ALL_MEMBERS = 109; 4815702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_PLAYLISTS = 110; 4816702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_PLAYLISTS_ID = 111; 4817702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_PLAYLISTS_ID_MEMBERS = 112; 4818702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_PLAYLISTS_ID_MEMBERS_ID = 113; 4819702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ARTISTS = 114; 4820702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ARTISTS_ID = 115; 4821702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ALBUMS = 116; 4822702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ALBUMS_ID = 117; 4823702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ARTISTS_ID_ALBUMS = 118; 4824702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ALBUMART = 119; 4825702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ALBUMART_ID = 120; 482671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen private static final int AUDIO_ALBUMART_FILE_ID = 121; 4827702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4828702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int VIDEO_MEDIA = 200; 4829702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int VIDEO_MEDIA_ID = 201; 4830b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private static final int VIDEO_THUMBNAILS = 202; 4831b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private static final int VIDEO_THUMBNAILS_ID = 203; 4832702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4833702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int VOLUMES = 300; 4834702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int VOLUMES_ID = 301; 4835702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4836a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen private static final int AUDIO_SEARCH_LEGACY = 400; 4837a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen private static final int AUDIO_SEARCH_BASIC = 401; 4838a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen private static final int AUDIO_SEARCH_FANCY = 402; 4839702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4840702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int MEDIA_SCANNER = 500; 4841702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 48420027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen private static final int FS_ID = 600; 4843704a8b507b7aa61a09457075ed6f80c95914d731Marco Nelissen private static final int VERSION = 601; 48440027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen 484516dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood private static final int FILES = 700; 484616dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood private static final int FILES_ID = 701; 4847a36cfaef630ef5df7bef80b25f6bd493d040c7e4Brian Muramatsu 4848e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood // Used only by the MTP implementation 4849e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood private static final int MTP_OBJECTS = 702; 4850e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood private static final int MTP_OBJECTS_ID = 703; 4851e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood private static final int MTP_OBJECT_REFERENCES = 704; 4852819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood // UsbReceiver calls insert() and delete() with this URI to tell us 4853819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood // when MTP is connected and disconnected 4854819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood private static final int MTP_CONNECTED = 705; 4855b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 4856702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final UriMatcher URI_MATCHER = 4857702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project new UriMatcher(UriMatcher.NO_MATCH); 4858702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4859b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private static final String[] ID_PROJECTION = new String[] { 4860b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen MediaStore.MediaColumns._ID 4861b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen }; 4862b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 48631d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood private static final String[] PATH_PROJECTION = new String[] { 48641d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood MediaStore.MediaColumns._ID, 48651d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood MediaStore.MediaColumns.DATA, 48661d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood }; 48671d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood 4868702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final String[] MIME_TYPE_PROJECTION = new String[] { 4869702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.MediaColumns._ID, // 0 4870702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.MediaColumns.MIME_TYPE, // 1 4871702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project }; 4872702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4873b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private static final String[] READY_FLAG_PROJECTION = new String[] { 4874b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen MediaStore.MediaColumns._ID, 4875b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen MediaStore.MediaColumns.DATA, 4876b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen Images.Media.MINI_THUMB_MAGIC 4877b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen }; 4878b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 4879e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood private static final String OBJECT_REFERENCES_QUERY = 4880afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "SELECT " + Audio.Playlists.Members.AUDIO_ID + " FROM audio_playlists_map" 4881afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + " WHERE " + Audio.Playlists.Members.PLAYLIST_ID + "=?" 4882afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + " ORDER BY " + Audio.Playlists.Members.PLAY_ORDER; 4883e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood 4884702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project static 4885702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project { 4886702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/images/media", IMAGES_MEDIA); 4887702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/images/media/#", IMAGES_MEDIA_ID); 4888702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/images/thumbnails", IMAGES_THUMBNAILS); 4889702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/images/thumbnails/#", IMAGES_THUMBNAILS_ID); 4890702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4891702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/media", AUDIO_MEDIA); 4892702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/media/#", AUDIO_MEDIA_ID); 4893702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/media/#/genres", AUDIO_MEDIA_ID_GENRES); 4894702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/media/#/genres/#", AUDIO_MEDIA_ID_GENRES_ID); 4895702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/media/#/playlists", AUDIO_MEDIA_ID_PLAYLISTS); 4896702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/media/#/playlists/#", AUDIO_MEDIA_ID_PLAYLISTS_ID); 4897702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/genres", AUDIO_GENRES); 4898702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/genres/#", AUDIO_GENRES_ID); 4899702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/genres/#/members", AUDIO_GENRES_ID_MEMBERS); 4900bfbc30ff3b9e3a96b08c525d0971d8d8543ab000Marco Nelissen URI_MATCHER.addURI("media", "*/audio/genres/all/members", AUDIO_GENRES_ALL_MEMBERS); 4901702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/playlists", AUDIO_PLAYLISTS); 4902702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/playlists/#", AUDIO_PLAYLISTS_ID); 4903702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/playlists/#/members", AUDIO_PLAYLISTS_ID_MEMBERS); 4904702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/playlists/#/members/#", AUDIO_PLAYLISTS_ID_MEMBERS_ID); 4905702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/artists", AUDIO_ARTISTS); 4906702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/artists/#", AUDIO_ARTISTS_ID); 4907702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/artists/#/albums", AUDIO_ARTISTS_ID_ALBUMS); 4908702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/albums", AUDIO_ALBUMS); 4909702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/albums/#", AUDIO_ALBUMS_ID); 4910702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/albumart", AUDIO_ALBUMART); 4911702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/albumart/#", AUDIO_ALBUMART_ID); 491271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen URI_MATCHER.addURI("media", "*/audio/media/#/albumart", AUDIO_ALBUMART_FILE_ID); 4913702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4914702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/video/media", VIDEO_MEDIA); 4915702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/video/media/#", VIDEO_MEDIA_ID); 4916b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen URI_MATCHER.addURI("media", "*/video/thumbnails", VIDEO_THUMBNAILS); 4917b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen URI_MATCHER.addURI("media", "*/video/thumbnails/#", VIDEO_THUMBNAILS_ID); 4918702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4919702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/media_scanner", MEDIA_SCANNER); 4920702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 49210027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen URI_MATCHER.addURI("media", "*/fs_id", FS_ID); 4922704a8b507b7aa61a09457075ed6f80c95914d731Marco Nelissen URI_MATCHER.addURI("media", "*/version", VERSION); 49230027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen 4924819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood URI_MATCHER.addURI("media", "*/mtp_connected", MTP_CONNECTED); 4925819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood 4926702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*", VOLUMES_ID); 4927702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", null, VOLUMES); 4928702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4929b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood // Used by MTP implementation 493016dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood URI_MATCHER.addURI("media", "*/file", FILES); 493116dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood URI_MATCHER.addURI("media", "*/file/#", FILES_ID); 4932e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood URI_MATCHER.addURI("media", "*/object", MTP_OBJECTS); 4933e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood URI_MATCHER.addURI("media", "*/object/#", MTP_OBJECTS_ID); 4934e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood URI_MATCHER.addURI("media", "*/object/#/references", MTP_OBJECT_REFERENCES); 4935b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 4936a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen /** 4937a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen * @deprecated use the 'basic' or 'fancy' search Uris instead 4938a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen */ 4939702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/" + SearchManager.SUGGEST_URI_PATH_QUERY, 4940a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen AUDIO_SEARCH_LEGACY); 4941702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/" + SearchManager.SUGGEST_URI_PATH_QUERY + "/*", 4942a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen AUDIO_SEARCH_LEGACY); 4943a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen 4944a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // used for search suggestions 4945a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen URI_MATCHER.addURI("media", "*/audio/search/" + SearchManager.SUGGEST_URI_PATH_QUERY, 4946a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen AUDIO_SEARCH_BASIC); 4947a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen URI_MATCHER.addURI("media", "*/audio/search/" + SearchManager.SUGGEST_URI_PATH_QUERY + 4948a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "/*", AUDIO_SEARCH_BASIC); 4949a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen 4950a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // used by the music app's search activity 4951a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen URI_MATCHER.addURI("media", "*/audio/search/fancy", AUDIO_SEARCH_FANCY); 4952a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen URI_MATCHER.addURI("media", "*/audio/search/fancy/*", AUDIO_SEARCH_FANCY); 4953702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 495410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen 495510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen @Override 495610af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { 495710af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen Collection<DatabaseHelper> foo = mDatabases.values(); 495810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen for (DatabaseHelper dbh: foo) { 495910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen StringBuilder s = new StringBuilder(); 496010af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen s.append(dbh.mName); 496110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen s.append(": "); 496210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen SQLiteDatabase db = dbh.getReadableDatabase(); 496310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen if (db == null) { 496410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen s.append("null"); 496510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen } else { 496610af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen s.append("version " + db.getVersion() + ", "); 496710af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen Cursor c = db.query("files", new String[] {"count(*)"}, null, null, null, null, null); 496810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen try { 496910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen if (c != null && c.moveToFirst()) { 497010af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen int num = c.getInt(0); 497110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen s.append(num + " rows, "); 497210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen } else { 497310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen s.append("couldn't get row count, "); 497410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen } 497510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen } finally { 497610af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen if (c != null) { 497710af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen c.close(); 497810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen } 497910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen } 498010af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen s.append(dbh.mNumInserts + " inserts, "); 498110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen s.append(dbh.mNumUpdates + " updates, "); 498210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen s.append(dbh.mNumDeletes + " deletes, "); 498310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen s.append(dbh.mNumQueries + " queries, "); 498410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen if (dbh.mScanStartTime != 0) { 498510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen s.append("scan started " + DateUtils.formatDateTime(getContext(), 498610af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen dbh.mScanStartTime / 1000, 498710af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen DateUtils.FORMAT_SHOW_DATE 498810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen | DateUtils.FORMAT_SHOW_TIME 498910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen | DateUtils.FORMAT_ABBREV_ALL)); 499010af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen if (dbh.mScanStopTime < dbh.mScanStartTime) { 499110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen s.append(" (ongoing)"); 499210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen } else { 499310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen s.append(" (" + DateUtils.formatElapsedTime( 499410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen (dbh.mScanStopTime - dbh.mScanStartTime) / 1000000) + ")"); 499510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen } 499610af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen } 499710af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen } 499810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen writer.println(s); 499910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen } 500010af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen if (mMediaScannerVolume != null) { 500110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen writer.println("Scanning: " + mMediaScannerVolume); 500210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen } 500310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen } 5004702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project} 5005