MediaProvider.java revision 988280a7b7cba5888b943a6db05aab703fd9c35a
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 19007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkeyimport static android.Manifest.permission.ACCESS_CACHE_FILESYSTEM; 20007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkeyimport static android.Manifest.permission.READ_EXTERNAL_STORAGE; 21007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkeyimport static android.Manifest.permission.WRITE_EXTERNAL_STORAGE; 22007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkeyimport static android.os.ParcelFileDescriptor.MODE_READ_WRITE; 23007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkeyimport static android.os.ParcelFileDescriptor.MODE_WRITE_ONLY; 24007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey 25702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.app.SearchManager; 26bdd3b8337b01920822c128b1ad1be202e22d070cOwen Linimport android.content.BroadcastReceiver; 27bdd3b8337b01920822c128b1ad1be202e22d070cOwen Linimport android.content.ComponentName; 28bdd3b8337b01920822c128b1ad1be202e22d070cOwen Linimport android.content.ContentProvider; 29bdd3b8337b01920822c128b1ad1be202e22d070cOwen Linimport android.content.ContentProviderOperation; 30bdd3b8337b01920822c128b1ad1be202e22d070cOwen Linimport android.content.ContentProviderResult; 31bdd3b8337b01920822c128b1ad1be202e22d070cOwen Linimport android.content.ContentResolver; 32bdd3b8337b01920822c128b1ad1be202e22d070cOwen Linimport android.content.ContentUris; 33bdd3b8337b01920822c128b1ad1be202e22d070cOwen Linimport android.content.ContentValues; 34bdd3b8337b01920822c128b1ad1be202e22d070cOwen Linimport android.content.Context; 35bdd3b8337b01920822c128b1ad1be202e22d070cOwen Linimport android.content.Intent; 36bdd3b8337b01920822c128b1ad1be202e22d070cOwen Linimport android.content.IntentFilter; 37bdd3b8337b01920822c128b1ad1be202e22d070cOwen Linimport android.content.OperationApplicationException; 38bdd3b8337b01920822c128b1ad1be202e22d070cOwen Linimport android.content.ServiceConnection; 39ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwoodimport android.content.SharedPreferences; 40bdd3b8337b01920822c128b1ad1be202e22d070cOwen Linimport android.content.UriMatcher; 4190c7da0610b7c3f4d9f4f3b2767e0bae5f3ab258Marco Nelissenimport android.content.pm.PackageManager.NameNotFoundException; 4270676508bd3a081edd909875e141f2c48d79c1acDaniel Lehmannimport android.content.res.Resources; 43702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.database.Cursor; 44ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissenimport android.database.DatabaseUtils; 450027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissenimport android.database.MatrixCursor; 46702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.database.sqlite.SQLiteDatabase; 47702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.database.sqlite.SQLiteOpenHelper; 48702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.database.sqlite.SQLiteQueryBuilder; 49702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.graphics.Bitmap; 50702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.graphics.BitmapFactory; 51b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwoodimport android.media.MediaFile; 52702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.media.MediaScanner; 5338b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissenimport android.media.MediaScannerConnection; 5438b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissenimport android.media.MediaScannerConnection.MediaScannerConnectionClient; 55b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chenimport android.media.MiniThumbFile; 5690345783ad297da6059398cab174687de6f36a5bMike Lockwoodimport android.mtp.MtpConstants; 579be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwoodimport android.mtp.MtpStorage; 58702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.net.Uri; 59702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.Binder; 6038b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissenimport android.os.Bundle; 61702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.Environment; 62702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.FileUtils; 63702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.Handler; 64ab43e1853533e4d9352c251d53c36fb645077e43Chih-Chung Changimport android.os.HandlerThread; 65702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.Message; 66702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.ParcelFileDescriptor; 67702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.Process; 68d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwoodimport android.os.RemoteException; 6910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissenimport android.os.SystemClock; 70c47e4f2921312098eddc5fe49b080e0f2df60e81Mike Lockwoodimport android.os.storage.StorageManager; 711f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwoodimport android.os.storage.StorageVolume; 72ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwoodimport android.preference.PreferenceManager; 73702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.BaseColumns; 74702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.MediaStore; 75702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.MediaStore.Audio; 764eff7fef57715b2247f9cfc98c7f69809ab35adeMarco Nelissenimport android.provider.MediaStore.Audio.Playlists; 77a2466a7a8613b61fa570a4e68bff9460c1ab1920Owen Linimport android.provider.MediaStore.Files; 7870676508bd3a081edd909875e141f2c48d79c1acDaniel Lehmannimport android.provider.MediaStore.Files.FileColumns; 79702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.MediaStore.Images; 8070676508bd3a081edd909875e141f2c48d79c1acDaniel Lehmannimport android.provider.MediaStore.Images.ImageColumns; 81702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.MediaStore.MediaColumns; 82702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.MediaStore.Video; 83702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.text.TextUtils; 8410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissenimport android.text.format.DateUtils; 85702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.util.Log; 86702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 87702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.io.File; 8810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissenimport java.io.FileDescriptor; 89702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.io.FileInputStream; 90702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.io.FileNotFoundException; 91702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.io.IOException; 92702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.io.OutputStream; 9310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissenimport java.io.PrintWriter; 94702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.text.Collator; 95cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissenimport java.util.ArrayList; 9610af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissenimport java.util.Collection; 97702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.util.HashMap; 98702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.util.HashSet; 99702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.util.Iterator; 100f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissenimport java.util.List; 10138b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissenimport java.util.Locale; 102b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chenimport java.util.PriorityQueue; 1038a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huberimport java.util.Stack; 104702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 105166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissenimport libcore.io.ErrnoException; 106166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissenimport libcore.io.Libcore; 107166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen 108702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project/** 109702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Media content provider. See {@link android.provider.MediaStore} for details. 110702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Separate databases are kept for each external storage card we see (using the 111702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * card's ID as an index). The content visible at content://media/external/... 112702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * changes with the card. 113702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 114702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectpublic class MediaProvider extends ContentProvider { 115702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final Uri MEDIA_URI = Uri.parse("content://media"); 116702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final Uri ALBUMART_URI = Uri.parse("content://media/external/audio/albumart"); 117b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private static final int ALBUM_THUMB = 1; 118b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private static final int IMAGE_THUMB = 2; 119702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 120702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final HashMap<String, String> sArtistAlbumsMap = new HashMap<String, String>(); 121d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen private static final HashMap<String, String> sFolderArtMap = new HashMap<String, String>(); 122702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 123007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey /** Resolved canonical path to external storage. */ 124007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey private static final String sExternalPath; 125007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey /** Resolved canonical path to cache storage. */ 126007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey private static final String sCachePath; 127007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey 128007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey static { 129007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey try { 130007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey sExternalPath = Environment.getExternalStorageDirectory().getCanonicalPath(); 131007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey sCachePath = Environment.getDownloadCacheDirectory().getCanonicalPath(); 132007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey } catch (IOException e) { 133007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey throw new RuntimeException("Unable to resolve canonical paths", e); 134007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey } 135007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey } 136007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey 1377f36494e085c26c69cd5925e54028822025eff29Marco Nelissen // In memory cache of path<->id mappings, to speed up inserts during media scan 1387f36494e085c26c69cd5925e54028822025eff29Marco Nelissen HashMap<String, Long> mDirectoryCache = new HashMap<String, Long>(); 1397f36494e085c26c69cd5925e54028822025eff29Marco Nelissen 1408a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // A HashSet of paths that are pending creation of album art thumbnails. 1418a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber private HashSet mPendingThumbs = new HashSet(); 1428a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 1438a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // A Stack of outstanding thumbnail requests. 1448a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber private Stack mThumbRequestStack = new Stack(); 1458a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 14620434e032e498b716f87cce2f23dd646819218bfRay Chen // The lock of mMediaThumbQueue protects both mMediaThumbQueue and mCurrentThumbRequest. 14720434e032e498b716f87cce2f23dd646819218bfRay Chen private MediaThumbRequest mCurrentThumbRequest = null; 148b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private PriorityQueue<MediaThumbRequest> mMediaThumbQueue = 149b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen new PriorityQueue<MediaThumbRequest>(MediaThumbRequest.PRIORITY_NORMAL, 150b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen MediaThumbRequest.getComparator()); 151b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 152f7cc647081f0421c0247de275fa0754b29938c07Mike Lockwood private boolean mCaseInsensitivePaths; 1539be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood private static String[] mExternalStoragePaths; 15417ad80b32f839ccddac3911799ff732d1ca3a006Mike Lockwood 155a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // For compatibility with the approximately 0 apps that used mediaprovider search in 156a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // releases 1.0, 1.1 or 1.5 157a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen private String[] mSearchColsLegacy = new String[] { 158a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen android.provider.BaseColumns._ID, 159a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen MediaStore.Audio.Media.MIME_TYPE, 160a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "(CASE WHEN grouporder=1 THEN " + R.drawable.ic_search_category_music_artist + 161a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen " ELSE CASE WHEN grouporder=2 THEN " + R.drawable.ic_search_category_music_album + 162a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen " ELSE " + R.drawable.ic_search_category_music_song + " END END" + 163a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen ") AS " + SearchManager.SUGGEST_COLUMN_ICON_1, 164a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "0 AS " + SearchManager.SUGGEST_COLUMN_ICON_2, 165a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "text1 AS " + SearchManager.SUGGEST_COLUMN_TEXT_1, 166a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "text1 AS " + SearchManager.SUGGEST_COLUMN_QUERY, 167a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "CASE when grouporder=1 THEN data1 ELSE artist END AS data1", 168a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "CASE when grouporder=1 THEN data2 ELSE " + 169a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "CASE WHEN grouporder=2 THEN NULL ELSE album END END AS data2", 170a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "match as ar", 171a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen SearchManager.SUGGEST_COLUMN_INTENT_DATA, 172a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "grouporder", 173ea74c8add2d5b4215dfeb69183632d9e9797ac5aMarco Nelissen "NULL AS itemorder" // We should be sorting by the artist/album/title keys, but that 174ea74c8add2d5b4215dfeb69183632d9e9797ac5aMarco Nelissen // column is not available here, and the list is already sorted. 175a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen }; 176a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen private String[] mSearchColsFancy = new String[] { 177a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen android.provider.BaseColumns._ID, 178a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen MediaStore.Audio.Media.MIME_TYPE, 179a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen MediaStore.Audio.Artists.ARTIST, 180a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen MediaStore.Audio.Albums.ALBUM, 181a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen MediaStore.Audio.Media.TITLE, 182a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "data1", 183a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "data2", 184a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen }; 18563f748ff8b258d9110038778a006b3000164fbeeSatish Sampath // If this array gets changed, please update the constant below to point to the correct item. 186a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen private String[] mSearchColsBasic = new String[] { 187a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen android.provider.BaseColumns._ID, 188a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen MediaStore.Audio.Media.MIME_TYPE, 189a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "(CASE WHEN grouporder=1 THEN " + R.drawable.ic_search_category_music_artist + 190a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen " ELSE CASE WHEN grouporder=2 THEN " + R.drawable.ic_search_category_music_album + 191a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen " ELSE " + R.drawable.ic_search_category_music_song + " END END" + 192a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen ") AS " + SearchManager.SUGGEST_COLUMN_ICON_1, 193a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "text1 AS " + SearchManager.SUGGEST_COLUMN_TEXT_1, 194a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "text1 AS " + SearchManager.SUGGEST_COLUMN_QUERY, 19563f748ff8b258d9110038778a006b3000164fbeeSatish Sampath "(CASE WHEN grouporder=1 THEN '%1'" + // %1 gets replaced with localized string. 19663f748ff8b258d9110038778a006b3000164fbeeSatish Sampath " ELSE CASE WHEN grouporder=3 THEN artist || ' - ' || album" + 197e31cfb1a2c21e7ac7a646d40afbb48f49fab6907Marco Nelissen " ELSE CASE WHEN text2!='" + MediaStore.UNKNOWN_STRING + "' THEN text2" + 19863f748ff8b258d9110038778a006b3000164fbeeSatish Sampath " ELSE NULL END END END) AS " + SearchManager.SUGGEST_COLUMN_TEXT_2, 199a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen SearchManager.SUGGEST_COLUMN_INTENT_DATA 200a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen }; 20163f748ff8b258d9110038778a006b3000164fbeeSatish Sampath // Position of the TEXT_2 item in the above array. 20263f748ff8b258d9110038778a006b3000164fbeeSatish Sampath private final int SEARCH_COLUMN_BASIC_TEXT2 = 5; 203a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen 204a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen private static final String[] sMediaTableColumns = new String[] { 20516dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood FileColumns._ID, 206afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood FileColumns.MEDIA_TYPE, 2071717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood }; 2081717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood 2097f36494e085c26c69cd5925e54028822025eff29Marco Nelissen private static final String[] sIdOnlyColumn = new String[] { 2107f36494e085c26c69cd5925e54028822025eff29Marco Nelissen FileColumns._ID 2117f36494e085c26c69cd5925e54028822025eff29Marco Nelissen }; 2127f36494e085c26c69cd5925e54028822025eff29Marco Nelissen 213166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen private static final String[] sDataOnlyColumn = new String[] { 214166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen FileColumns.DATA 215166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen }; 216166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen 217a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen private static final String[] sMediaTypeDataId = new String[] { 218a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen FileColumns.MEDIA_TYPE, 219a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen FileColumns.DATA, 220a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen FileColumns._ID 2214eff7fef57715b2247f9cfc98c7f69809ab35adeMarco Nelissen }; 2224eff7fef57715b2247f9cfc98c7f69809ab35adeMarco Nelissen 2234eff7fef57715b2247f9cfc98c7f69809ab35adeMarco Nelissen private static final String[] sPlaylistIdPlayOrder = new String[] { 2244eff7fef57715b2247f9cfc98c7f69809ab35adeMarco Nelissen Playlists.Members.PLAYLIST_ID, 2254eff7fef57715b2247f9cfc98c7f69809ab35adeMarco Nelissen Playlists.Members.PLAY_ORDER 2264eff7fef57715b2247f9cfc98c7f69809ab35adeMarco Nelissen }; 227a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen 228a9c4e330dacb37cfffa9c00f7da83cafde4accefMarco Nelissen private Uri mAlbumArtBaseUri = Uri.parse("content://media/external/audio/albumart"); 229a9c4e330dacb37cfffa9c00f7da83cafde4accefMarco Nelissen 230702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private BroadcastReceiver mUnmountReceiver = new BroadcastReceiver() { 231702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 232702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public void onReceive(Context context, Intent intent) { 233702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (intent.getAction().equals(Intent.ACTION_MEDIA_EJECT)) { 2341f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood StorageVolume storage = (StorageVolume)intent.getParcelableExtra( 2351f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood StorageVolume.EXTRA_STORAGE_VOLUME); 2361f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood // If primary external storage is ejected, then remove the external volume 2371f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood // notify all cursors backed by data on that volume. 2381f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood if (storage.getPath().equals(mExternalStoragePaths[0])) { 2391f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood detachVolume(Uri.parse("content://media/external")); 2401f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood sFolderArtMap.clear(); 2411f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood MiniThumbFile.reset(); 2421f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood } else { 2431f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood // If secondary external storage is ejected, then we delete all database 2441f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood // entries for that storage from the files table. 2451f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood synchronized (mDatabases) { 2461f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood DatabaseHelper database = mDatabases.get(EXTERNAL_VOLUME); 2471f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood Uri uri = Uri.parse("file://" + storage.getPath()); 2481f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood if (database != null) { 2491f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood try { 2501f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood // Send media scanner started and stopped broadcasts for apps that rely 2511f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood // on these Intents for coarse grained media database notifications. 2521f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood context.sendBroadcast( 2531f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood new Intent(Intent.ACTION_MEDIA_SCANNER_STARTED, uri)); 2541f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood 2551f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood // don't send objectRemoved events - MTP be sending StorageRemoved anyway 2561f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood mDisableMtpObjectCallbacks = true; 2571f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood Log.d(TAG, "deleting all entries for storage " + storage); 2581f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood SQLiteDatabase db = database.getWritableDatabase(); 2594b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood // First clear the file path to disable the _DELETE_FILE database hook. 2604b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood // We do this to avoid deleting files if the volume is remounted while 2614b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood // we are still processing the unmount event. 2624b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood ContentValues values = new ContentValues(); 2634b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood values.put(Files.FileColumns.DATA, ""); 2644b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood String where = FileColumns.STORAGE_ID + "=?"; 2654b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood String[] whereArgs = new String[] { Integer.toString(storage.getStorageId()) }; 2664b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood db.update("files", values, where, whereArgs); 2674b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood // now delete the records 2684b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood db.delete("files", where, whereArgs); 2694b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood // notify on media Uris as well as the files Uri 2704b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood context.getContentResolver().notifyChange( 2714b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood Audio.Media.getContentUri(EXTERNAL_VOLUME), null); 2724b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood context.getContentResolver().notifyChange( 2734b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood Images.Media.getContentUri(EXTERNAL_VOLUME), null); 2744b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood context.getContentResolver().notifyChange( 2754b230ed7c44706e56574d8d7481169b0ad2d0108Mike Lockwood Video.Media.getContentUri(EXTERNAL_VOLUME), null); 2761f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood context.getContentResolver().notifyChange( 2771f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood Files.getContentUri(EXTERNAL_VOLUME), null); 2781f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood } catch (Exception e) { 2791f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood Log.e(TAG, "exception deleting storage entries", e); 2801f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood } finally { 2811f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood context.sendBroadcast( 2821f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood new Intent(Intent.ACTION_MEDIA_SCANNER_FINISHED, uri)); 2831f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood mDisableMtpObjectCallbacks = false; 2841f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood } 2851f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood } 2861f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood } 2871f3014aa084584f4b0e788e3a67c19057b9ea292Mike Lockwood } 288702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 289702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 290702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project }; 291702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 292d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood // set to disable sending events when the operation originates from MTP 293d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood private boolean mDisableMtpObjectCallbacks; 294d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 295d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood private final SQLiteDatabase.CustomFunction mObjectRemovedCallback = 296d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood new SQLiteDatabase.CustomFunction() { 297d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood public void callback(String[] args) { 2987f36494e085c26c69cd5925e54028822025eff29Marco Nelissen // We could remove only the deleted entry from the cache, but that 2997f36494e085c26c69cd5925e54028822025eff29Marco Nelissen // requires the path, which we don't have here, so instead we just 3007f36494e085c26c69cd5925e54028822025eff29Marco Nelissen // clear the entire cache. 3017f36494e085c26c69cd5925e54028822025eff29Marco Nelissen // TODO: include the path in the callback and only remove the affected 3027f36494e085c26c69cd5925e54028822025eff29Marco Nelissen // entry from the cache 3037f36494e085c26c69cd5925e54028822025eff29Marco Nelissen mDirectoryCache.clear(); 304d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood // do nothing if the operation originated from MTP 305d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood if (mDisableMtpObjectCallbacks) return; 306d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 307d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood Log.d(TAG, "object removed " + args[0]); 308d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood IMtpService mtpService = mMtpService; 309d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood if (mtpService != null) { 310d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood try { 311d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood sendObjectRemoved(Integer.parseInt(args[0])); 312d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } catch (NumberFormatException e) { 313d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood Log.e(TAG, "NumberFormatException in mObjectRemovedCallback", e); 314d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 315d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 316d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 317d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood }; 318d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 319702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 320702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Wrapper class for a specific database (associated with one particular 321702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * external card, or with internal storage). Can open the actual database 322702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * on demand, create and upgrade the schema, etc. 323702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 324fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn static final class DatabaseHelper extends SQLiteOpenHelper { 325702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final Context mContext; 3265524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood final String mName; 327702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final boolean mInternal; // True if this is the internal database 328fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn final boolean mEarlyUpgrade; 329fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn final SQLiteDatabase.CustomFunction mObjectRemovedCallback; 3305524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood boolean mUpgradeAttempted; // Used for upgrade error handling 33110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen int mNumQueries; 33210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen int mNumUpdates; 33310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen int mNumInserts; 33410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen int mNumDeletes; 33510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen long mScanStartTime; 33610af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen long mScanStopTime; 337702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 338702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // In memory caches of artist and album data. 339702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project HashMap<String, Long> mArtistCache = new HashMap<String, Long>(); 340702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project HashMap<String, Long> mAlbumCache = new HashMap<String, Long>(); 341702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 342fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn public DatabaseHelper(Context context, String name, boolean internal, 343fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn boolean earlyUpgrade, 344fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn SQLiteDatabase.CustomFunction objectRemovedCallback) { 34590c7da0610b7c3f4d9f4f3b2767e0bae5f3ab258Marco Nelissen super(context, name, null, getDatabaseVersion(context)); 346702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mContext = context; 3475524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood mName = name; 348702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mInternal = internal; 349fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn mEarlyUpgrade = earlyUpgrade; 350fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn mObjectRemovedCallback = objectRemovedCallback; 3510e2a2386b39972286df21f4db5a9dd1df548c34dJeff Brown setWriteAheadLoggingEnabled(true); 352702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 353702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 354702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 355702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Creates database the first time we try to open it. 356702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 357702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 358702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public void onCreate(final SQLiteDatabase db) { 35990c7da0610b7c3f4d9f4f3b2767e0bae5f3ab258Marco Nelissen updateDatabase(mContext, db, mInternal, 0, getDatabaseVersion(mContext)); 360702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 361702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 362702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 363702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Updates the database format when a new content provider is used 364702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * with an older database format. 365702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 366702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 367702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public void onUpgrade(final SQLiteDatabase db, final int oldV, final int newV) { 3685524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood mUpgradeAttempted = true; 36990c7da0610b7c3f4d9f4f3b2767e0bae5f3ab258Marco Nelissen updateDatabase(mContext, db, mInternal, oldV, newV); 370702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 371702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 372db8357b2b2888ce3778278e9cd9e698347ca6105Owen Lin @Override 373db8357b2b2888ce3778278e9cd9e698347ca6105Owen Lin public synchronized SQLiteDatabase getWritableDatabase() { 3745524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood SQLiteDatabase result = null; 3755524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood mUpgradeAttempted = false; 3765524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood try { 3775524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood result = super.getWritableDatabase(); 3785524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood } catch (Exception e) { 3795524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood if (!mUpgradeAttempted) { 3805524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood Log.e(TAG, "failed to open database " + mName, e); 3815524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood return null; 3825524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood } 3835524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood } 3845524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood 3855524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood // If we failed to open the database during an upgrade, delete the file and try again. 3865524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood // This will result in the creation of a fresh database, which will be repopulated 3875524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood // when the media scanner runs. 3885524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood if (result == null && mUpgradeAttempted) { 3895524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood mContext.getDatabasePath(mName).delete(); 3905524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood result = super.getWritableDatabase(); 3915524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood } 3925524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood return result; 3935524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood } 3945524b8957701b458a24605ff4f1d953e7b847c8fMike Lockwood 395702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 396993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood * For devices that have removable storage, we support keeping multiple databases 397993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood * to allow users to switch between a number of cards. 398993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood * On such devices, touch this particular database and garbage collect old databases. 399702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * An LRU cache system is used to clean up databases for old external 400702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * storage volumes. 401702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 402702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 403702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public void onOpen(SQLiteDatabase db) { 40436d7136bebac6ea5738fb653a74dcd6c71e4cd58Dmitry Dolinsky 405702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (mInternal) return; // The internal database is kept separately. 406702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 407fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn if (mEarlyUpgrade) return; // Doing early upgrade. 408fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn 409fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn if (mObjectRemovedCallback != null) { 410fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn db.addCustomFunction("_OBJECT_REMOVED", 1, mObjectRemovedCallback); 411fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn } 412d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 413993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood // the code below is only needed on devices with removable storage 414993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood if (!Environment.isExternalStorageRemovable()) return; 415993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood 416702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // touch the database file to show it is most recently used 417702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File file = new File(db.getPath()); 418702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long now = System.currentTimeMillis(); 419702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project file.setLastModified(now); 420702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 421702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // delete least recently used databases if we are over the limit 422702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String[] databases = mContext.databaseList(); 423702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int count = databases.length; 424702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int limit = MAX_EXTERNAL_DATABASES; 425702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 426702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // delete external databases that have not been used in the past two months 427702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long twoMonthsAgo = now - OBSOLETE_DATABASE_DB; 428702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project for (int i = 0; i < databases.length; i++) { 429702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File other = mContext.getDatabasePath(databases[i]); 430702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (INTERNAL_DATABASE_NAME.equals(databases[i]) || file.equals(other)) { 431702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project databases[i] = null; 432702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count--; 433702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (file.equals(other)) { 434702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // reduce limit to account for the existence of the database we 435702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // are about to open, which we removed from the list. 436702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project limit--; 437702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 438702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 439702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long time = other.lastModified(); 440702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (time < twoMonthsAgo) { 441702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (LOCAL_LOGV) Log.v(TAG, "Deleting old database " + databases[i]); 442702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mContext.deleteDatabase(databases[i]); 443702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project databases[i] = null; 444702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count--; 445702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 446702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 447702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 448702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 449702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // delete least recently used databases until 450702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // we are no longer over the limit 451702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project while (count > limit) { 452702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int lruIndex = -1; 453702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long lruTime = 0; 454702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 455702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project for (int i = 0; i < databases.length; i++) { 456702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (databases[i] != null) { 457702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long time = mContext.getDatabasePath(databases[i]).lastModified(); 458702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (lruTime == 0 || time < lruTime) { 459702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project lruIndex = i; 460702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project lruTime = time; 461702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 462702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 463702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 464702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 465702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // delete least recently used database 466702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (lruIndex != -1) { 467702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (LOCAL_LOGV) Log.v(TAG, "Deleting old database " + databases[lruIndex]); 468702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mContext.deleteDatabase(databases[lruIndex]); 469702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project databases[lruIndex] = null; 470702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count--; 471702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 472702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 473702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 474702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 475702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 47634be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood // synchronize on mMtpServiceConnection when accessing mMtpService 477d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood private IMtpService mMtpService; 478d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 479d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood private final ServiceConnection mMtpServiceConnection = new ServiceConnection() { 480d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood public void onServiceConnected(ComponentName className, android.os.IBinder service) { 48134be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood synchronized (this) { 48234be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood mMtpService = IMtpService.Stub.asInterface(service); 48334be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood } 484d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 485d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 486d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood public void onServiceDisconnected(ComponentName className) { 48734be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood synchronized (this) { 48834be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood mMtpService = null; 48934be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood } 490d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 491d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood }; 492d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 493ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood private static final String[] sDefaultFolderNames = { 494ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood Environment.DIRECTORY_MUSIC, 495ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood Environment.DIRECTORY_PODCASTS, 496ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood Environment.DIRECTORY_RINGTONES, 497ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood Environment.DIRECTORY_ALARMS, 498ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood Environment.DIRECTORY_NOTIFICATIONS, 499ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood Environment.DIRECTORY_PICTURES, 500ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood Environment.DIRECTORY_MOVIES, 501ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood Environment.DIRECTORY_DOWNLOADS, 502ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood Environment.DIRECTORY_DCIM, 503ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood }; 504ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood 505ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood // creates default folders (Music, Downloads, etc) 50610af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen private void createDefaultFolders(DatabaseHelper helper, SQLiteDatabase db) { 507ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood // Use a SharedPreference to ensure we only do this once. 508ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood // We don't want to annoy the user by recreating the directories 509ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood // after she has deleted them. 510ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext()); 511ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood if (prefs.getInt("created_default_folders", 0) == 0) { 512ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood for (String folderName : sDefaultFolderNames) { 513ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood File file = Environment.getExternalStoragePublicDirectory(folderName); 514ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood if (!file.exists()) { 515ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood file.mkdirs(); 51610af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen insertDirectory(helper, db, file.getAbsolutePath()); 517ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood } 518ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood } 519ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood 520ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood SharedPreferences.Editor e = prefs.edit(); 521ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood e.clear(); 522ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood e.putInt("created_default_folders", 1); 523ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood e.commit(); 524ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood } 525ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood } 526ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood 5279311c7ff9d35ca3acc908da3da7a79fbf7a8da6bMarco Nelissen public static int getDatabaseVersion(Context context) { 52890c7da0610b7c3f4d9f4f3b2767e0bae5f3ab258Marco Nelissen try { 52990c7da0610b7c3f4d9f4f3b2767e0bae5f3ab258Marco Nelissen return context.getPackageManager().getPackageInfo( 53090c7da0610b7c3f4d9f4f3b2767e0bae5f3ab258Marco Nelissen context.getPackageName(), 0).versionCode; 53190c7da0610b7c3f4d9f4f3b2767e0bae5f3ab258Marco Nelissen } catch (NameNotFoundException e) { 53290c7da0610b7c3f4d9f4f3b2767e0bae5f3ab258Marco Nelissen throw new RuntimeException("couldn't get version code for " + context); 53390c7da0610b7c3f4d9f4f3b2767e0bae5f3ab258Marco Nelissen } 53490c7da0610b7c3f4d9f4f3b2767e0bae5f3ab258Marco Nelissen } 53590c7da0610b7c3f4d9f4f3b2767e0bae5f3ab258Marco Nelissen 536702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 537702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public boolean onCreate() { 538d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood final Context context = getContext(); 539d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 540acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen sArtistAlbumsMap.put(MediaStore.Audio.Albums._ID, "audio.album_id AS " + 541acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen MediaStore.Audio.Albums._ID); 542702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Albums.ALBUM, "album"); 543702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Albums.ALBUM_KEY, "album_key"); 544acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen sArtistAlbumsMap.put(MediaStore.Audio.Albums.FIRST_YEAR, "MIN(year) AS " + 545702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.Audio.Albums.FIRST_YEAR); 546acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen sArtistAlbumsMap.put(MediaStore.Audio.Albums.LAST_YEAR, "MAX(year) AS " + 547702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.Audio.Albums.LAST_YEAR); 548702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Media.ARTIST, "artist"); 549702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Media.ARTIST_ID, "artist"); 550702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Media.ARTIST_KEY, "artist_key"); 551acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen sArtistAlbumsMap.put(MediaStore.Audio.Albums.NUMBER_OF_SONGS, "count(*) AS " + 552acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen MediaStore.Audio.Albums.NUMBER_OF_SONGS); 553acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen sArtistAlbumsMap.put(MediaStore.Audio.Albums.ALBUM_ART, "album_art._data AS " + 554acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen MediaStore.Audio.Albums.ALBUM_ART); 555702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 55663f748ff8b258d9110038778a006b3000164fbeeSatish Sampath mSearchColsBasic[SEARCH_COLUMN_BASIC_TEXT2] = 55763f748ff8b258d9110038778a006b3000164fbeeSatish Sampath mSearchColsBasic[SEARCH_COLUMN_BASIC_TEXT2].replaceAll( 558d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood "%1", context.getString(R.string.artist_label)); 559702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mDatabases = new HashMap<String, DatabaseHelper>(); 560702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project attachVolume(INTERNAL_VOLUME); 561702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 562702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project IntentFilter iFilter = new IntentFilter(Intent.ACTION_MEDIA_EJECT); 563702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project iFilter.addDataScheme("file"); 564d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood context.registerReceiver(mUnmountReceiver, iFilter); 565702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 5667d4f72d8ab71e28e9d40da87ec8c75ded254dd08Dianne Hackborn mCaseInsensitivePaths = true; 5674f2186758ee1c6eaa702bf1511b233b26143b631Mike Lockwood 568c47e4f2921312098eddc5fe49b080e0f2df60e81Mike Lockwood StorageManager storageManager = 569c47e4f2921312098eddc5fe49b080e0f2df60e81Mike Lockwood (StorageManager)context.getSystemService(Context.STORAGE_SERVICE); 570c47e4f2921312098eddc5fe49b080e0f2df60e81Mike Lockwood mExternalStoragePaths = storageManager.getVolumePaths(); 5719be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood 572702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // open external database if external storage is mounted 573702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String state = Environment.getExternalStorageState(); 574702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (Environment.MEDIA_MOUNTED.equals(state) || 575702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) { 576702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project attachVolume(EXTERNAL_VOLUME); 577702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 578702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 579ab43e1853533e4d9352c251d53c36fb645077e43Chih-Chung Chang HandlerThread ht = new HandlerThread("thumbs thread", Process.THREAD_PRIORITY_BACKGROUND); 580ab43e1853533e4d9352c251d53c36fb645077e43Chih-Chung Chang ht.start(); 581ab43e1853533e4d9352c251d53c36fb645077e43Chih-Chung Chang mThumbHandler = new Handler(ht.getLooper()) { 582702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 583702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public void handleMessage(Message msg) { 584b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (msg.what == IMAGE_THUMB) { 585b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen synchronized (mMediaThumbQueue) { 58620434e032e498b716f87cce2f23dd646819218bfRay Chen mCurrentThumbRequest = mMediaThumbQueue.poll(); 587b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 58820434e032e498b716f87cce2f23dd646819218bfRay Chen if (mCurrentThumbRequest == null) { 589b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen Log.w(TAG, "Have message but no request?"); 590b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } else { 591b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen try { 59220434e032e498b716f87cce2f23dd646819218bfRay Chen File origFile = new File(mCurrentThumbRequest.mPath); 5934d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen if (origFile.exists() && origFile.length() > 0) { 59420434e032e498b716f87cce2f23dd646819218bfRay Chen mCurrentThumbRequest.execute(); 5954d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen } else { 5964d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen // original file hasn't been stored yet 5974d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen synchronized (mMediaThumbQueue) { 59820434e032e498b716f87cce2f23dd646819218bfRay Chen Log.w(TAG, "original file hasn't been stored yet: " + mCurrentThumbRequest.mPath); 5994d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen } 6004d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen } 601b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } catch (IOException ex) { 6021d6eba9e1e28c722aa73a651d86a2efe2b937bf2Ray Chen Log.w(TAG, ex); 6031d6eba9e1e28c722aa73a651d86a2efe2b937bf2Ray Chen } catch (UnsupportedOperationException ex) { 6041d6eba9e1e28c722aa73a651d86a2efe2b937bf2Ray Chen // This could happen if we unplug the sd card during insert/update/delete 6051d6eba9e1e28c722aa73a651d86a2efe2b937bf2Ray Chen // See getDatabaseForUri. 6061d6eba9e1e28c722aa73a651d86a2efe2b937bf2Ray Chen Log.w(TAG, ex); 60722c5095b70a9fd6304fcf2366e8e40e37ae95764Erik Rydgren } catch (OutOfMemoryError err) { 60822c5095b70a9fd6304fcf2366e8e40e37ae95764Erik Rydgren /* 60922c5095b70a9fd6304fcf2366e8e40e37ae95764Erik Rydgren * Note: Catching Errors is in most cases considered 61022c5095b70a9fd6304fcf2366e8e40e37ae95764Erik Rydgren * bad practice. However, in this case it is 61122c5095b70a9fd6304fcf2366e8e40e37ae95764Erik Rydgren * motivated by the fact that corrupt or very large 61222c5095b70a9fd6304fcf2366e8e40e37ae95764Erik Rydgren * images may cause a huge allocation to be 61322c5095b70a9fd6304fcf2366e8e40e37ae95764Erik Rydgren * requested and denied. The bitmap handling API in 61422c5095b70a9fd6304fcf2366e8e40e37ae95764Erik Rydgren * Android offers no other way to guard against 61522c5095b70a9fd6304fcf2366e8e40e37ae95764Erik Rydgren * these problems than by catching OutOfMemoryError. 61622c5095b70a9fd6304fcf2366e8e40e37ae95764Erik Rydgren */ 61722c5095b70a9fd6304fcf2366e8e40e37ae95764Erik Rydgren Log.w(TAG, err); 618b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } finally { 61920434e032e498b716f87cce2f23dd646819218bfRay Chen synchronized (mCurrentThumbRequest) { 62020434e032e498b716f87cce2f23dd646819218bfRay Chen mCurrentThumbRequest.mState = MediaThumbRequest.State.DONE; 62120434e032e498b716f87cce2f23dd646819218bfRay Chen mCurrentThumbRequest.notifyAll(); 622b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 623b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 624b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 625b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } else if (msg.what == ALBUM_THUMB) { 626b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen ThumbData d; 627b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen synchronized (mThumbRequestStack) { 628b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen d = (ThumbData)mThumbRequestStack.pop(); 629b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 6308a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 631b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen makeThumbInternal(d); 632b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen synchronized (mPendingThumbs) { 633b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen mPendingThumbs.remove(d.path); 634b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 6358a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 636702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 637702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project }; 638702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 639702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return true; 640702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 641702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 642afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood private static final String IMAGE_COLUMNS = 643afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "_data,_size,_display_name,mime_type,title,date_added," + 644afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "date_modified,description,picasa_id,isprivate,latitude,longitude," + 645bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang "datetaken,orientation,mini_thumb_magic,bucket_id,bucket_display_name," + 646bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang "width,height"; 647bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang 648bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang private static final String IMAGE_COLUMNSv407 = 649bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang "_data,_size,_display_name,mime_type,title,date_added," + 650bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang "date_modified,description,picasa_id,isprivate,latitude,longitude," + 651afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "datetaken,orientation,mini_thumb_magic,bucket_id,bucket_display_name"; 652afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 653805b0b734dd5a73e2f77cd8d818a07a8627a8c1eMarco Nelissen private static final String AUDIO_COLUMNSv99 = 654afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "_data,_display_name,_size,mime_type,date_added," + 655afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "date_modified,title,title_key,duration,artist_id,composer,album_id," + 656afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "track,year,is_ringtone,is_music,is_alarm,is_notification,is_podcast," + 657afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "bookmark"; 658afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 659805b0b734dd5a73e2f77cd8d818a07a8627a8c1eMarco Nelissen private static final String AUDIO_COLUMNSv100 = 660805b0b734dd5a73e2f77cd8d818a07a8627a8c1eMarco Nelissen "_data,_display_name,_size,mime_type,date_added," + 661805b0b734dd5a73e2f77cd8d818a07a8627a8c1eMarco Nelissen "date_modified,title,title_key,duration,artist_id,composer,album_id," + 662805b0b734dd5a73e2f77cd8d818a07a8627a8c1eMarco Nelissen "track,year,is_ringtone,is_music,is_alarm,is_notification,is_podcast," + 663805b0b734dd5a73e2f77cd8d818a07a8627a8c1eMarco Nelissen "bookmark,album_artist"; 664805b0b734dd5a73e2f77cd8d818a07a8627a8c1eMarco Nelissen 665957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang private static final String AUDIO_COLUMNSv405 = 666957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang "_data,_display_name,_size,mime_type,date_added,is_drm," + 667957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang "date_modified,title,title_key,duration,artist_id,composer,album_id," + 668957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang "track,year,is_ringtone,is_music,is_alarm,is_notification,is_podcast," + 669957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang "bookmark,album_artist"; 670957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang 671afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood private static final String VIDEO_COLUMNS = 672afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "_data,_display_name,_size,mime_type,date_added,date_modified," + 673afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "title,duration,artist,album,resolution,description,isprivate,tags," + 674afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "category,language,mini_thumb_data,latitude,longitude,datetaken," + 675bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang "mini_thumb_magic,bucket_id,bucket_display_name,bookmark,width," + 676bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang "height"; 677bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang 678bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang private static final String VIDEO_COLUMNSv407 = 679bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang "_data,_display_name,_size,mime_type,date_added,date_modified," + 680bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang "title,duration,artist,album,resolution,description,isprivate,tags," + 681bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang "category,language,mini_thumb_data,latitude,longitude,datetaken," + 682afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "mini_thumb_magic,bucket_id,bucket_display_name, bookmark"; 683afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 684afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood private static final String PLAYLIST_COLUMNS = "_data,name,date_added,date_modified"; 685afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 686702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 687702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * This method takes care of updating all the tables in the database to the 688702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * current version, creating them if necessary. 689702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * This method can only update databases at schema 63 or higher, which was 690702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * created August 1, 2008. Older database will be cleared and recreated. 691702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param db Database 692702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param internal True if this is the internal media database 693702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 69490c7da0610b7c3f4d9f4f3b2767e0bae5f3ab258Marco Nelissen private static void updateDatabase(Context context, SQLiteDatabase db, boolean internal, 695702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int fromVersion, int toVersion) { 696702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 697702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // sanity checks 69890c7da0610b7c3f4d9f4f3b2767e0bae5f3ab258Marco Nelissen int dbversion = getDatabaseVersion(context); 69990c7da0610b7c3f4d9f4f3b2767e0bae5f3ab258Marco Nelissen if (toVersion != dbversion) { 70090c7da0610b7c3f4d9f4f3b2767e0bae5f3ab258Marco Nelissen Log.e(TAG, "Illegal update request. Got " + toVersion + ", expected " + dbversion); 701702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalArgumentException(); 702702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else if (fromVersion > toVersion) { 70395ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen Log.e(TAG, "Illegal update request: can't downgrade from " + fromVersion + 704702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " to " + toVersion + ". Did you forget to wipe data?"); 705702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalArgumentException(); 706702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 707988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen long startTime = SystemClock.currentTimeMicro(); 708702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 709d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood // Revisions 84-86 were a failed attempt at supporting the "album artist" id3 tag. 710acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // We can't downgrade from those revisions, so start over. 711022eb71bfe8ec65b8817eaa432a530194210ec23Marco Nelissen // (the initial change to do this was wrong, so now we actually need to start over 712022eb71bfe8ec65b8817eaa432a530194210ec23Marco Nelissen // if the database version is 84-89) 713bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin // Post-gingerbread, revisions 91-94 were broken in a way that is not easy to repair. 714bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin // However version 91 was reused in a divergent development path for gingerbread, 715bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin // so we need to support upgrades from 91. 716bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin // Therefore we will only force a reset for versions 92 - 94. 717d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood if (fromVersion < 63 || (fromVersion >= 84 && fromVersion <= 89) || 718bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin (fromVersion >= 92 && fromVersion <= 94)) { 719702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Drop everything and start over. 720702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Log.i(TAG, "Upgrading media database from version " + 721702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project fromVersion + " to " + toVersion + ", which will destroy all old data"); 722d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen fromVersion = 63; 723702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS images"); 724702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS images_cleanup"); 725702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS thumbnails"); 726702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS thumbnails_cleanup"); 727702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS audio_meta"); 728702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS artists"); 729702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS albums"); 730702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS album_art"); 731702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP VIEW IF EXISTS artist_info"); 732702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP VIEW IF EXISTS album_info"); 733702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP VIEW IF EXISTS artists_albums_map"); 734702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS audio_meta_cleanup"); 735702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS audio_genres"); 736702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS audio_genres_map"); 737702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS audio_genres_cleanup"); 738702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS audio_playlists"); 739702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS audio_playlists_map"); 740702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS audio_playlists_cleanup"); 741702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS albumart_cleanup1"); 742702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS albumart_cleanup2"); 743702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS video"); 744702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS video_cleanup"); 745cec8df8a90209fc4df5d1ff5f02dc364d0d2edc6Mike Lockwood db.execSQL("DROP TABLE IF EXISTS objects"); 7469ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood db.execSQL("DROP TRIGGER IF EXISTS images_objects_cleanup"); 7479ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood db.execSQL("DROP TRIGGER IF EXISTS audio_objects_cleanup"); 7489ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood db.execSQL("DROP TRIGGER IF EXISTS video_objects_cleanup"); 7499ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood db.execSQL("DROP TRIGGER IF EXISTS playlists_objects_cleanup"); 750702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 751702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS images (" + 752702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 753702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_data TEXT," + 754702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_size INTEGER," + 755702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_display_name TEXT," + 756702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "mime_type TEXT," + 757702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "title TEXT," + 758702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_added INTEGER," + 759702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_modified INTEGER," + 760702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "description TEXT," + 761702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "picasa_id TEXT," + 762702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "isprivate INTEGER," + 763702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "latitude DOUBLE," + 764702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "longitude DOUBLE," + 765702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "datetaken INTEGER," + 766702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "orientation INTEGER," + 767702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "mini_thumb_magic INTEGER," + 768702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "bucket_id TEXT," + 769702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "bucket_display_name TEXT" + 770702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 771702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 772702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE INDEX IF NOT EXISTS mini_thumb_magic_index on images(mini_thumb_magic);"); 773702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 774702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS images_cleanup DELETE ON images " + 775702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 776702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE FROM thumbnails WHERE image_id = old._id;" + 777702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT _DELETE_FILE(old._data);" + 778702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 779702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 780b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // create image thumbnail table 781702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS thumbnails (" + 782702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 783702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_data TEXT," + 784702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "image_id INTEGER," + 785702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "kind INTEGER," + 786702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "width INTEGER," + 787702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "height INTEGER" + 788702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 789702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 790702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE INDEX IF NOT EXISTS image_id_index on thumbnails(image_id);"); 791702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 792702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS thumbnails_cleanup DELETE ON thumbnails " + 793702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 794702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT _DELETE_FILE(old._data);" + 795702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 796702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 797702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains meta data about audio files 798702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS audio_meta (" + 799702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 800216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen "_data TEXT UNIQUE NOT NULL," + 801702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_display_name TEXT," + 802702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_size INTEGER," + 803702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "mime_type TEXT," + 804702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_added INTEGER," + 805702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_modified INTEGER," + 806702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "title TEXT NOT NULL," + 807702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "title_key TEXT NOT NULL," + 808702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "duration INTEGER," + 809702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "artist_id INTEGER," + 810702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "composer TEXT," + 811702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "album_id INTEGER," + 812702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "track INTEGER," + // track is an integer to allow proper sorting 813702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "year INTEGER CHECK(year!=0)," + 814702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "is_ringtone INTEGER," + 815702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "is_music INTEGER," + 816702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "is_alarm INTEGER," + 817702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "is_notification INTEGER" + 818702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 819702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 820702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains a sort/group "key" and the preferred display name for artists 821702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS artists (" + 822702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "artist_id INTEGER PRIMARY KEY," + 823702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "artist_key TEXT NOT NULL UNIQUE," + 824702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "artist TEXT NOT NULL" + 825702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 826702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 827702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains a sort/group "key" and the preferred display name for albums 828702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS albums (" + 829702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "album_id INTEGER PRIMARY KEY," + 830702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "album_key TEXT NOT NULL UNIQUE," + 831702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "album TEXT NOT NULL" + 832702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 833702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 834702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS album_art (" + 835702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "album_id INTEGER PRIMARY KEY," + 836702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_data TEXT" + 837702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 838702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 839702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project recreateAudioView(db); 84095ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen 841702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 842702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Provides some extra info about artists, like the number of tracks 843702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // and albums for this artist 844702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE VIEW IF NOT EXISTS artist_info AS " + 845702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT artist_id AS _id, artist, artist_key, " + 846acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen "COUNT(DISTINCT album) AS number_of_albums, " + 847702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "COUNT(*) AS number_of_tracks FROM audio WHERE is_music=1 "+ 848702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "GROUP BY artist_key;"); 849702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 850702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Provides extra info albums, such as the number of tracks 851702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE VIEW IF NOT EXISTS album_info AS " + 852702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT audio.album_id AS _id, album, album_key, " + 853702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "MIN(year) AS minyear, " + 854702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "MAX(year) AS maxyear, artist, artist_id, artist_key, " + 855702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "count(*) AS " + MediaStore.Audio.Albums.NUMBER_OF_SONGS + 856702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ",album_art._data AS album_art" + 857702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " FROM audio LEFT OUTER JOIN album_art ON audio.album_id=album_art.album_id" + 858702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " WHERE is_music=1 GROUP BY audio.album_id;"); 859702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 860acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // For a given artist_id, provides the album_id for albums on 861acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // which the artist appears. 862acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("CREATE VIEW IF NOT EXISTS artists_albums_map AS " + 863acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen "SELECT DISTINCT artist_id, album_id FROM audio_meta;"); 864acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen 865702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /* 866702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Only external media volumes can handle genres, playlists, etc. 867702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 868702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!internal) { 869702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Cleans up when an audio file is deleted 870702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS audio_meta_cleanup DELETE ON audio_meta " + 871702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 872702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE FROM audio_genres_map WHERE audio_id = old._id;" + 873702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE FROM audio_playlists_map WHERE audio_id = old._id;" + 874702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 875702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 876702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains audio genre definitions 877702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS audio_genres (" + 878702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 879702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "name TEXT NOT NULL" + 880702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 881702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 88278b2885edc406273d688536b0eadfea006b20662Marco Nelissen // Contains mappings between audio genres and audio files 883702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS audio_genres_map (" + 884702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 885702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_id INTEGER NOT NULL," + 886702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "genre_id INTEGER NOT NULL" + 887702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 888702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 889702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Cleans up when an audio genre is delete 890702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS audio_genres_cleanup DELETE ON audio_genres " + 891702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 892702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE FROM audio_genres_map WHERE genre_id = old._id;" + 893702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 894702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 895702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains audio playlist definitions 896702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS audio_playlists (" + 897702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 898702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_data TEXT," + // _data is path for file based playlists, or null 899702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "name TEXT NOT NULL," + 900702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_added INTEGER," + 901702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_modified INTEGER" + 902702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 903702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 904702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains mappings between audio playlists and audio files 905702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS audio_playlists_map (" + 906702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 907702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_id INTEGER NOT NULL," + 908702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "playlist_id INTEGER NOT NULL," + 909702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "play_order INTEGER NOT NULL" + 910702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 911702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 912702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Cleans up when an audio playlist is deleted 913702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS audio_playlists_cleanup DELETE ON audio_playlists " + 914702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 915702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE FROM audio_playlists_map WHERE playlist_id = old._id;" + 916702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT _DELETE_FILE(old._data);" + 917702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 918702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 919702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Cleans up album_art table entry when an album is deleted 920702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS albumart_cleanup1 DELETE ON albums " + 921702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 922702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE FROM album_art WHERE album_id = old.album_id;" + 923702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 924702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 925702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Cleans up album_art when an album is deleted 926702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS albumart_cleanup2 DELETE ON album_art " + 927702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 928702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT _DELETE_FILE(old._data);" + 929702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 930702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 931702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 932702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains meta data about video files 933702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS video (" + 934702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 935702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_data TEXT NOT NULL," + 936702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_display_name TEXT," + 937702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_size INTEGER," + 938702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "mime_type TEXT," + 939702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_added INTEGER," + 940702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_modified INTEGER," + 941702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "title TEXT," + 942702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "duration INTEGER," + 943702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "artist TEXT," + 944702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "album TEXT," + 945702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "resolution TEXT," + 946702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "description TEXT," + 947702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "isprivate INTEGER," + // for YouTube videos 948702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "tags TEXT," + // for YouTube videos 949702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "category TEXT," + // for YouTube videos 950702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "language TEXT," + // for YouTube videos 951702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "mini_thumb_data TEXT," + 952702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "latitude DOUBLE," + 953702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "longitude DOUBLE," + 954702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "datetaken INTEGER," + 955702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "mini_thumb_magic INTEGER" + 956702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 957702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 958702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS video_cleanup DELETE ON video " + 959702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 960702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT _DELETE_FILE(old._data);" + 961702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 962702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 963702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 964702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // At this point the database is at least at schema version 63 (it was 965702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // either created at version 63 by the code above, or was already at 966702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // version 63 or later) 967702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 968702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 64) { 969702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // create the index that updates the database to schema version 64 970702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE INDEX IF NOT EXISTS sort_index on images(datetaken ASC, _id ASC);"); 971702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 972702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 973acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen /* 974acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen * Android 1.0 shipped with database version 64 975acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen */ 976acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen 977702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 65) { 978702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // create the index that updates the database to schema version 65 979702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE INDEX IF NOT EXISTS titlekey_index on audio_meta(title_key);"); 980702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 981702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 982403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen // In version 66, originally we updateBucketNames(db, "images"), 983403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen // but we need to do it in version 89 and therefore save the update here. 984702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 985702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 67) { 986702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // create the indices that update the database to schema version 67 987702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE INDEX IF NOT EXISTS albumkey_index on albums(album_key);"); 988702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE INDEX IF NOT EXISTS artistkey_index on artists(artist_key);"); 989702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 990702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 991702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 68) { 992702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Create bucket_id and bucket_display_name columns for the video table. 993702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("ALTER TABLE video ADD COLUMN bucket_id TEXT;"); 994702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("ALTER TABLE video ADD COLUMN bucket_display_name TEXT"); 995403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen 996403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen // In version 68, originally we updateBucketNames(db, "video"), 997403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen // but we need to do it in version 89 and therefore save the update here. 998702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 999702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1000702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 69) { 1001702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project updateDisplayName(db, "images"); 1002702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1003702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1004702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 70) { 1005702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Create bookmark column for the video table. 1006702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("ALTER TABLE video ADD COLUMN bookmark INTEGER;"); 1007702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 100895ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen 1009702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 71) { 1010702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // There is no change to the database schema, however a code change 1011702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // fixed parsing of metadata for certain files bought from the 1012702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // iTunes music store, so we want to rescan files that might need it. 1013702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // We do this by clearing the modification date in the database for 1014702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // those files, so that the media scanner will see them as updated 1015702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // and rescan them. 1016702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("UPDATE audio_meta SET date_modified=0 WHERE _id IN (" + 1017702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT _id FROM audio where mime_type='audio/mp4' AND " + 1018e31cfb1a2c21e7ac7a646d40afbb48f49fab6907Marco Nelissen "artist='" + MediaStore.UNKNOWN_STRING + "' AND " + 1019e31cfb1a2c21e7ac7a646d40afbb48f49fab6907Marco Nelissen "album='" + MediaStore.UNKNOWN_STRING + "'" + 1020702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 1021702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 102295ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen 1023702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 72) { 1024702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Create is_podcast and bookmark columns for the audio table. 1025702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("ALTER TABLE audio_meta ADD COLUMN is_podcast INTEGER;"); 1026702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("UPDATE audio_meta SET is_podcast=1 WHERE _data LIKE '%/podcasts/%';"); 1027702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("UPDATE audio_meta SET is_music=0 WHERE is_podcast=1" + 1028702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " AND _data NOT LIKE '%/music/%';"); 1029702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("ALTER TABLE audio_meta ADD COLUMN bookmark INTEGER;"); 1030702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1031702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // New columns added to tables aren't visible in views on those tables 1032702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // without opening and closing the database (or using the 'vacuum' command, 1033702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // which we can't do here because all this code runs inside a transaction). 1034702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // To work around this, we drop and recreate the affected view and trigger. 1035702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project recreateAudioView(db); 1036702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 103795ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen 1038acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen /* 1039acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen * Android 1.5 shipped with database version 72 1040acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen */ 1041acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen 10428d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen if (fromVersion < 73) { 10438d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen // There is no change to the database schema, but we now do case insensitive 10448d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen // matching of folder names when determining whether something is music, a 10458d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen // ringtone, podcast, etc, so we might need to reclassify some files. 10468d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen db.execSQL("UPDATE audio_meta SET is_music=1 WHERE is_music=0 AND " + 10478d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen "_data LIKE '%/music/%';"); 10488d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen db.execSQL("UPDATE audio_meta SET is_ringtone=1 WHERE is_ringtone=0 AND " + 10498d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen "_data LIKE '%/ringtones/%';"); 10508d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen db.execSQL("UPDATE audio_meta SET is_notification=1 WHERE is_notification=0 AND " + 10518d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen "_data LIKE '%/notifications/%';"); 10528d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen db.execSQL("UPDATE audio_meta SET is_alarm=1 WHERE is_alarm=0 AND " + 10538d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen "_data LIKE '%/alarms/%';"); 10548d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen db.execSQL("UPDATE audio_meta SET is_podcast=1 WHERE is_podcast=0 AND " + 10558d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen "_data LIKE '%/podcasts/%';"); 10568d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen } 1057a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen 1058a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen if (fromVersion < 74) { 1059a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // This view is used instead of the audio view by the union below, to force 1060a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // sqlite to use the title_key index. This greatly reduces memory usage 1061a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // (no separate copy pass needed for sorting, which could cause errors on 1062a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // large datasets) and improves speed (by about 35% on a large dataset) 1063a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen db.execSQL("CREATE VIEW IF NOT EXISTS searchhelpertitle AS SELECT * FROM audio " + 1064a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "ORDER BY title_key;"); 1065a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen 1066a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen db.execSQL("CREATE VIEW IF NOT EXISTS search AS " + 1067a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "SELECT _id," + 1068a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "'artist' AS mime_type," + 1069a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist," + 1070a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS album," + 1071a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS title," + 1072a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist AS text1," + 1073a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS text2," + 1074a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "number_of_albums AS data1," + 1075a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "number_of_tracks AS data2," + 1076a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist_key AS match," + 1077a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "'content://media/external/audio/artists/'||_id AS suggest_intent_data," + 1078a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "1 AS grouporder " + 1079e31cfb1a2c21e7ac7a646d40afbb48f49fab6907Marco Nelissen "FROM artist_info WHERE (artist!='" + MediaStore.UNKNOWN_STRING + "') " + 1080a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "UNION ALL " + 1081a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "SELECT _id," + 1082a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "'album' AS mime_type," + 1083a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist," + 1084a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "album," + 1085a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS title," + 1086a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "album AS text1," + 1087a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist AS text2," + 1088a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS data1," + 1089a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS data2," + 1090a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist_key||' '||album_key AS match," + 1091a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "'content://media/external/audio/albums/'||_id AS suggest_intent_data," + 1092a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "2 AS grouporder " + 1093e31cfb1a2c21e7ac7a646d40afbb48f49fab6907Marco Nelissen "FROM album_info WHERE (album!='" + MediaStore.UNKNOWN_STRING + "') " + 1094a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "UNION ALL " + 1095a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "SELECT searchhelpertitle._id AS _id," + 1096a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "mime_type," + 1097a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist," + 1098a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "album," + 1099a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "title," + 1100a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "title AS text1," + 1101a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist AS text2," + 1102a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS data1," + 1103a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS data2," + 1104a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist_key||' '||album_key||' '||title_key AS match," + 1105a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "'content://media/external/audio/media/'||searchhelpertitle._id AS " + 1106a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "suggest_intent_data," + 1107a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "3 AS grouporder " + 1108a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "FROM searchhelpertitle WHERE (title != '') " 1109a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen ); 1110a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen } 111159948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen 111259948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen if (fromVersion < 75) { 111395ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen // Force a rescan of the audio entries so we can apply the new logic to 111459948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // distinguish same-named albums. 111559948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen db.execSQL("UPDATE audio_meta SET date_modified=0;"); 111659948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen db.execSQL("DELETE FROM albums"); 111759948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen } 111815d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen 111915d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen if (fromVersion < 76) { 112015d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen // We now ignore double quotes when building the key, so we have to remove all of them 112115d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen // from existing keys. 112215d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen db.execSQL("UPDATE audio_meta SET title_key=" + 112315d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen "REPLACE(title_key,x'081D08C29F081D',x'081D') " + 112415d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen "WHERE title_key LIKE '%'||x'081D08C29F081D'||'%';"); 112515d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen db.execSQL("UPDATE albums SET album_key=" + 112615d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen "REPLACE(album_key,x'081D08C29F081D',x'081D') " + 112715d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen "WHERE album_key LIKE '%'||x'081D08C29F081D'||'%';"); 112815d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen db.execSQL("UPDATE artists SET artist_key=" + 112915d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen "REPLACE(artist_key,x'081D08C29F081D',x'081D') " + 113015d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen "WHERE artist_key LIKE '%'||x'081D08C29F081D'||'%';"); 113115d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen } 1132b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1133acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen /* 1134acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen * Android 1.6 shipped with database version 76 1135acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen */ 1136acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen 1137b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (fromVersion < 77) { 1138b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // create video thumbnail table 1139b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen db.execSQL("CREATE TABLE IF NOT EXISTS videothumbnails (" + 1140b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "_id INTEGER PRIMARY KEY," + 1141b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "_data TEXT," + 1142b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "video_id INTEGER," + 1143b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "kind INTEGER," + 1144b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "width INTEGER," + 1145b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "height INTEGER" + 1146b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen ");"); 1147b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1148b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen db.execSQL("CREATE INDEX IF NOT EXISTS video_id_index on videothumbnails(video_id);"); 1149b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1150b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen db.execSQL("CREATE TRIGGER IF NOT EXISTS videothumbnails_cleanup DELETE ON videothumbnails " + 1151b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "BEGIN " + 1152b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "SELECT _DELETE_FILE(old._data);" + 1153b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "END"); 1154b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 11551769168ade7b67f8695a4e4f3c69625aca0811d5Ray Chen 1156acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen /* 1157acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen * Android 2.0 and 2.0.1 shipped with database version 77 1158acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen */ 1159acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen 11601769168ade7b67f8695a4e4f3c69625aca0811d5Ray Chen if (fromVersion < 78) { 1161044b029d9023f55e8e8861ed2f6e192f1b34f9bbRay Chen // Force a rescan of the video entries so we can update 11621769168ade7b67f8695a4e4f3c69625aca0811d5Ray Chen // latest changed DATE_TAKEN units (in milliseconds). 11631769168ade7b67f8695a4e4f3c69625aca0811d5Ray Chen db.execSQL("UPDATE video SET date_modified=0;"); 11641769168ade7b67f8695a4e4f3c69625aca0811d5Ray Chen } 1165268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen 1166acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen /* 1167acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen * Android 2.1 shipped with database version 78 1168acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen */ 1169acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen 1170268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen if (fromVersion < 79) { 1171268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen // move /sdcard/albumthumbs to 1172268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen // /sdcard/Android/data/com.android.providers.media/albumthumbs, 1173268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen // and update the database accordingly 1174268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen 11759be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood String oldthumbspath = mExternalStoragePaths[0] + "/albumthumbs"; 11769be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood String newthumbspath = mExternalStoragePaths[0] + "/" + ALBUM_THUMB_FOLDER; 1177268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen File thumbsfolder = new File(oldthumbspath); 1178268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen if (thumbsfolder.exists()) { 1179268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen // move folder to its new location 1180268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen File newthumbsfolder = new File(newthumbspath); 1181268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen newthumbsfolder.getParentFile().mkdirs(); 1182268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen if(thumbsfolder.renameTo(newthumbsfolder)) { 1183268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen // update the database 1184268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen db.execSQL("UPDATE album_art SET _data=REPLACE(_data, '" + 1185268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen oldthumbspath + "','" + newthumbspath + "');"); 1186268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen } 1187268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen } 1188268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen } 1189044b029d9023f55e8e8861ed2f6e192f1b34f9bbRay Chen 1190044b029d9023f55e8e8861ed2f6e192f1b34f9bbRay Chen if (fromVersion < 80) { 1191044b029d9023f55e8e8861ed2f6e192f1b34f9bbRay Chen // Force rescan of image entries to update DATE_TAKEN as UTC timestamp. 1192044b029d9023f55e8e8861ed2f6e192f1b34f9bbRay Chen db.execSQL("UPDATE images SET date_modified=0;"); 1193044b029d9023f55e8e8861ed2f6e192f1b34f9bbRay Chen } 11940ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen 1195166a4e3cc66a645cc5e11d2f06d059512def0aceMarco Nelissen if (fromVersion < 81 && !internal) { 11960ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // Delete entries starting with /mnt/sdcard. This is for the benefit 11970ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // of users running builds between 2.0.1 and 2.1 final only, since 11980ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // users updating from 2.0 or earlier will not have such entries. 11990ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen 12000ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // First we need to update the _data fields in the affected tables, since 12010ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // otherwise deleting the entries will also delete the underlying files 12020ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // (via a trigger), and we want to keep them. 12030ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE audio_playlists SET _data='////' WHERE _data LIKE '/mnt/sdcard/%';"); 12040ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE images SET _data='////' WHERE _data LIKE '/mnt/sdcard/%';"); 12050ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE video SET _data='////' WHERE _data LIKE '/mnt/sdcard/%';"); 12060ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE videothumbnails SET _data='////' WHERE _data LIKE '/mnt/sdcard/%';"); 12070ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE thumbnails SET _data='////' WHERE _data LIKE '/mnt/sdcard/%';"); 12080ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE album_art SET _data='////' WHERE _data LIKE '/mnt/sdcard/%';"); 1209216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen db.execSQL("UPDATE audio_meta SET _data='////' WHERE _data LIKE '/mnt/sdcard/%';"); 12100ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // Once the paths have been renamed, we can safely delete the entries 12110ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE FROM audio_playlists WHERE _data IS '////';"); 12120ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE FROM images WHERE _data IS '////';"); 12130ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE FROM video WHERE _data IS '////';"); 12140ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE FROM videothumbnails WHERE _data IS '////';"); 12150ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE FROM thumbnails WHERE _data IS '////';"); 12160ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE FROM audio_meta WHERE _data IS '////';"); 12170ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE FROM album_art WHERE _data IS '////';"); 12180ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen 12190ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // rename existing entries starting with /sdcard to /mnt/sdcard 12200ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE audio_meta" + 12210ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen " SET _data='/mnt/sdcard'||SUBSTR(_data,8) WHERE _data LIKE '/sdcard/%';"); 12220ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE audio_playlists" + 12230ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen " SET _data='/mnt/sdcard'||SUBSTR(_data,8) WHERE _data LIKE '/sdcard/%';"); 12240ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE images" + 12250ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen " SET _data='/mnt/sdcard'||SUBSTR(_data,8) WHERE _data LIKE '/sdcard/%';"); 12260ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE video" + 12270ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen " SET _data='/mnt/sdcard'||SUBSTR(_data,8) WHERE _data LIKE '/sdcard/%';"); 12280ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE videothumbnails" + 12290ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen " SET _data='/mnt/sdcard'||SUBSTR(_data,8) WHERE _data LIKE '/sdcard/%';"); 12300ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE thumbnails" + 12310ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen " SET _data='/mnt/sdcard'||SUBSTR(_data,8) WHERE _data LIKE '/sdcard/%';"); 12320ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE album_art" + 12330ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen " SET _data='/mnt/sdcard'||SUBSTR(_data,8) WHERE _data LIKE '/sdcard/%';"); 12340ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen 12350ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // Delete albums and artists, then clear the modification time on songs, which 12360ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // will cause the media scanner to rescan everything, rebuilding the artist and 12370ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // album tables along the way, while preserving playlists. 12380ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // We need this rescan because ICU also changed, and now generates different 12390ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // collation keys 12400ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE from albums"); 12410ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE from artists"); 12420ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE audio_meta SET date_modified=0;"); 12430ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen } 124484403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen 124584403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen if (fromVersion < 82) { 1246acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // recreate this view with the correct "group by" specifier 124784403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen db.execSQL("DROP VIEW IF EXISTS artist_info"); 124884403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen db.execSQL("CREATE VIEW IF NOT EXISTS artist_info AS " + 124984403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen "SELECT artist_id AS _id, artist, artist_key, " + 1250acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen "COUNT(DISTINCT album_key) AS number_of_albums, " + 125184403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen "COUNT(*) AS number_of_tracks FROM audio WHERE is_music=1 "+ 125284403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen "GROUP BY artist_key;"); 125384403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen } 1254216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen 1255acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen /* we skipped over version 83, and reverted versions 84, 85 and 86 */ 1256ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen 1257ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen if (fromVersion < 87) { 1258ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen // The fastscroll thumb needs an index on the strings being displayed, 1259ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen // otherwise the queries it does to determine the correct position 1260ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen // becomes really inefficient 1261022eb71bfe8ec65b8817eaa432a530194210ec23Marco Nelissen db.execSQL("CREATE INDEX IF NOT EXISTS title_idx on audio_meta(title);"); 1262022eb71bfe8ec65b8817eaa432a530194210ec23Marco Nelissen db.execSQL("CREATE INDEX IF NOT EXISTS artist_idx on artists(artist);"); 1263022eb71bfe8ec65b8817eaa432a530194210ec23Marco Nelissen db.execSQL("CREATE INDEX IF NOT EXISTS album_idx on albums(album);"); 1264ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen } 1265216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen 1266acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen if (fromVersion < 88) { 1267acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // Clean up a few more things from versions 84/85/86, and recreate 1268acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // the few things worth keeping from those changes. 1269acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS albums_update1;"); 1270acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS albums_update2;"); 1271acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS albums_update3;"); 1272acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS albums_update4;"); 1273acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS artist_update1;"); 1274acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS artist_update2;"); 1275acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS artist_update3;"); 1276acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS artist_update4;"); 127716dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood db.execSQL("DROP VIEW IF EXISTS album_artists;"); 1278acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("CREATE INDEX IF NOT EXISTS album_id_idx on audio_meta(album_id);"); 1279acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("CREATE INDEX IF NOT EXISTS artist_id_idx on audio_meta(artist_id);"); 1280acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // For a given artist_id, provides the album_id for albums on 1281acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // which the artist appears. 1282acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("CREATE VIEW IF NOT EXISTS artists_albums_map AS " + 1283acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen "SELECT DISTINCT artist_id, album_id FROM audio_meta;"); 1284acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen } 1285403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen 1286fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood // In version 89, originally we updateBucketNames(db, "images") and 1287fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood // updateBucketNames(db, "video"), but in version 101 we now updateBucketNames 1288fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood // for all files and therefore can save the update here. 1289b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 1290b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood if (fromVersion < 91) { 1291bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin // Never query by mini_thumb_magic_index 1292bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin db.execSQL("DROP INDEX IF EXISTS mini_thumb_magic_index"); 1293bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin 1294bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin // sort the items by taken date in each bucket 1295bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin db.execSQL("CREATE INDEX IF NOT EXISTS image_bucket_index ON images(bucket_id, datetaken)"); 1296bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin db.execSQL("CREATE INDEX IF NOT EXISTS video_bucket_index ON video(bucket_id, datetaken)"); 1297bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin } 1298bdd3b8337b01920822c128b1ad1be202e22d070cOwen Lin 1299a36cfaef630ef5df7bef80b25f6bd493d040c7e4Brian Muramatsu 1300d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen // Gingerbread ended up going to version 100, but didn't yet have the "files" 1301d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen // table, so we need to create that if we're at 100 or lower. This means 1302d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen // we won't be able to upgrade pre-release Honeycomb. 1303d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen if (fromVersion <= 100) { 1304afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // Remove various stages of work in progress for MTP support 1305afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TABLE IF EXISTS objects"); 1306afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TABLE IF EXISTS files"); 130716dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood db.execSQL("DROP TRIGGER IF EXISTS images_objects_cleanup;"); 130816dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood db.execSQL("DROP TRIGGER IF EXISTS audio_objects_cleanup;"); 130916dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood db.execSQL("DROP TRIGGER IF EXISTS video_objects_cleanup;"); 131016dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood db.execSQL("DROP TRIGGER IF EXISTS playlists_objects_cleanup;"); 1311afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TRIGGER IF EXISTS files_cleanup_images;"); 1312afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TRIGGER IF EXISTS files_cleanup_audio;"); 1313afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TRIGGER IF EXISTS files_cleanup_video;"); 1314afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TRIGGER IF EXISTS files_cleanup_playlists;"); 1315afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TRIGGER IF EXISTS media_cleanup;"); 1316afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1317afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // Create a new table to manage all files in our storage. 1318afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // This contains a union of all the columns from the old 1319afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // images, audio_meta, videos and audio_playlist tables. 1320afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE TABLE files (" + 132100a22306f6c99d1f1b4424f8f6a1cad8fb332d85Ray Chen "_id INTEGER PRIMARY KEY AUTOINCREMENT," + 1322afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "_data TEXT," + // this can be null for playlists 1323afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "_size INTEGER," + 1324afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "format INTEGER," + 1325afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "parent INTEGER," + 1326afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "date_added INTEGER," + 1327afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "date_modified INTEGER," + 1328afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "mime_type TEXT," + 1329afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "title TEXT," + 1330afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "description TEXT," + 1331afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "_display_name TEXT," + 1332afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1333afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // for images 1334afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "picasa_id TEXT," + 1335afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "orientation INTEGER," + 1336afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1337afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // for images and video 1338afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "latitude DOUBLE," + 1339afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "longitude DOUBLE," + 1340afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "datetaken INTEGER," + 1341afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "mini_thumb_magic INTEGER," + 1342afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "bucket_id TEXT," + 1343afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "bucket_display_name TEXT," + 1344afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "isprivate INTEGER," + 1345afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1346afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // for audio 1347afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "title_key TEXT," + 1348afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "artist_id INTEGER," + 1349afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "album_id INTEGER," + 1350afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "composer TEXT," + 1351afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "track INTEGER," + 1352afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "year INTEGER CHECK(year!=0)," + 1353afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "is_ringtone INTEGER," + 1354afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "is_music INTEGER," + 1355afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "is_alarm INTEGER," + 1356afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "is_notification INTEGER," + 1357afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "is_podcast INTEGER," + 1358d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen "album_artist TEXT," + 1359afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1360afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // for audio and video 1361afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "duration INTEGER," + 1362afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "bookmark INTEGER," + 1363afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1364afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // for video 1365afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "artist TEXT," + 1366afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "album TEXT," + 1367afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "resolution TEXT," + 1368afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "tags TEXT," + 1369afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "category TEXT," + 1370afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "language TEXT," + 1371afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "mini_thumb_data TEXT," + 1372afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1373afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // for playlists 1374afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "name TEXT," + 1375afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1376afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // media_type is used by the views to emulate the old 1377afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // images, audio_meta, videos and audio_playlist tables. 1378afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "media_type INTEGER," + 1379afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1380afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // Value of _id from the old media table. 1381afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // Used only for updating other tables during database upgrade. 1382afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "old_id INTEGER" + 1383afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood ");"); 1384d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen 1385afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE INDEX path_index ON files(_data);"); 1386afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE INDEX media_type_index ON files(media_type);"); 1387afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1388afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // Copy all data from our obsolete tables to the new files table 138992be385568284e6351ab49f5799eca0e35b9d98dMike Lockwood 139092be385568284e6351ab49f5799eca0e35b9d98dMike Lockwood // Copy audio records first, preserving the _id column. 139192be385568284e6351ab49f5799eca0e35b9d98dMike Lockwood // We do this to maintain compatibility for content Uris for ringtones. 139292be385568284e6351ab49f5799eca0e35b9d98dMike Lockwood // Unfortunately we cannot do this for images and videos as well. 139392be385568284e6351ab49f5799eca0e35b9d98dMike Lockwood // We choose to do this for the audio table because the fragility of Uris 139492be385568284e6351ab49f5799eca0e35b9d98dMike Lockwood // for ringtones are the most common problem we need to avoid. 139592be385568284e6351ab49f5799eca0e35b9d98dMike Lockwood db.execSQL("INSERT INTO files (_id," + AUDIO_COLUMNSv99 + ",old_id,media_type)" + 139692be385568284e6351ab49f5799eca0e35b9d98dMike Lockwood " SELECT _id," + AUDIO_COLUMNSv99 + ",_id," + FileColumns.MEDIA_TYPE_AUDIO + 139792be385568284e6351ab49f5799eca0e35b9d98dMike Lockwood " FROM audio_meta;"); 139892be385568284e6351ab49f5799eca0e35b9d98dMike Lockwood 1399bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang db.execSQL("INSERT INTO files (" + IMAGE_COLUMNSv407 + ",old_id,media_type) SELECT " 1400bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang + IMAGE_COLUMNSv407 + ",_id," + FileColumns.MEDIA_TYPE_IMAGE + " FROM images;"); 1401bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang db.execSQL("INSERT INTO files (" + VIDEO_COLUMNSv407 + ",old_id,media_type) SELECT " 1402bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang + VIDEO_COLUMNSv407 + ",_id," + FileColumns.MEDIA_TYPE_VIDEO + " FROM video;"); 140316dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood if (!internal) { 1404afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("INSERT INTO files (" + PLAYLIST_COLUMNS + ",old_id,media_type) SELECT " 1405afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + PLAYLIST_COLUMNS + ",_id," + FileColumns.MEDIA_TYPE_PLAYLIST 1406afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + " FROM audio_playlists;"); 1407afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 140816dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood 1409afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // Delete the old tables 1410afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TABLE IF EXISTS images"); 1411afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TABLE IF EXISTS audio_meta"); 1412afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TABLE IF EXISTS video"); 1413afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TABLE IF EXISTS audio_playlists"); 141416dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood 1415afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // Create views to replace our old tables 1416bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang db.execSQL("CREATE VIEW images AS SELECT _id," + IMAGE_COLUMNSv407 + 1417afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood " FROM files WHERE " + FileColumns.MEDIA_TYPE + "=" 1418afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + FileColumns.MEDIA_TYPE_IMAGE + ";"); 1419d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen db.execSQL("CREATE VIEW audio_meta AS SELECT _id," + AUDIO_COLUMNSv100 + 1420d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen " FROM files WHERE " + FileColumns.MEDIA_TYPE + "=" 1421d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen + FileColumns.MEDIA_TYPE_AUDIO + ";"); 1422bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang db.execSQL("CREATE VIEW video AS SELECT _id," + VIDEO_COLUMNSv407 + 1423afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood " FROM files WHERE " + FileColumns.MEDIA_TYPE + "=" 1424afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + FileColumns.MEDIA_TYPE_VIDEO + ";"); 1425afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (!internal) { 1426afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE VIEW audio_playlists AS SELECT _id," + PLAYLIST_COLUMNS + 1427afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood " FROM files WHERE " + FileColumns.MEDIA_TYPE + "=" 1428afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + FileColumns.MEDIA_TYPE_PLAYLIST + ";"); 142916dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood } 143036339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood 14319491c3bd011644f5fe69fd47f73d0e1245b33febMarco Nelissen // create temporary index to make the updates go faster 14329491c3bd011644f5fe69fd47f73d0e1245b33febMarco Nelissen db.execSQL("CREATE INDEX tmp ON files(old_id);"); 14339491c3bd011644f5fe69fd47f73d0e1245b33febMarco Nelissen 1434afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // update the image_id column in the thumbnails table. 1435afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("UPDATE thumbnails SET image_id = (SELECT _id FROM files " 1436afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + "WHERE files.old_id = thumbnails.image_id AND files.media_type = " 1437afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + FileColumns.MEDIA_TYPE_IMAGE + ");"); 143836339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood 1439afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (!internal) { 1440d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen // update audio_id in the audio_genres_map table, and 1441d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen // audio_playlists_map tables and playlist_id in the audio_playlists_map table 1442afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("UPDATE audio_genres_map SET audio_id = (SELECT _id FROM files " 1443afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + "WHERE files.old_id = audio_genres_map.audio_id AND files.media_type = " 1444afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + FileColumns.MEDIA_TYPE_AUDIO + ");"); 1445afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("UPDATE audio_playlists_map SET audio_id = (SELECT _id FROM files " 1446afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + "WHERE files.old_id = audio_playlists_map.audio_id " 1447afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + "AND files.media_type = " + FileColumns.MEDIA_TYPE_AUDIO + ");"); 1448d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen db.execSQL("UPDATE audio_playlists_map SET playlist_id = (SELECT _id FROM files " 1449d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen + "WHERE files.old_id = audio_playlists_map.playlist_id " 1450d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen + "AND files.media_type = " + FileColumns.MEDIA_TYPE_PLAYLIST + ");"); 1451afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 1452afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1453afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // update video_id in the videothumbnails table. 1454afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("UPDATE videothumbnails SET video_id = (SELECT _id FROM files " 1455afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + "WHERE files.old_id = videothumbnails.video_id AND files.media_type = " 1456afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + FileColumns.MEDIA_TYPE_VIDEO + ");"); 1457afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 14589491c3bd011644f5fe69fd47f73d0e1245b33febMarco Nelissen // we don't need this index anymore now 14599491c3bd011644f5fe69fd47f73d0e1245b33febMarco Nelissen db.execSQL("DROP INDEX tmp;"); 14609491c3bd011644f5fe69fd47f73d0e1245b33febMarco Nelissen 1461afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // update indices to work on the files table 1462afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP INDEX IF EXISTS title_idx"); 1463afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP INDEX IF EXISTS album_id_idx"); 1464afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP INDEX IF EXISTS image_bucket_index"); 1465afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP INDEX IF EXISTS video_bucket_index"); 1466afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP INDEX IF EXISTS sort_index"); 1467afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP INDEX IF EXISTS titlekey_index"); 1468afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP INDEX IF EXISTS artist_id_idx"); 1469afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE INDEX title_idx ON files(title);"); 1470afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE INDEX album_id_idx ON files(album_id);"); 1471afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE INDEX bucket_index ON files(bucket_id, datetaken);"); 1472afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE INDEX sort_index ON files(datetaken ASC, _id ASC);"); 1473afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE INDEX titlekey_index ON files(title_key);"); 1474afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE INDEX artist_id_idx ON files(artist_id);"); 1475afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1476afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // Recreate triggers for our obsolete tables on the new files table 1477afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TRIGGER IF EXISTS images_cleanup"); 1478afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TRIGGER IF EXISTS audio_meta_cleanup"); 1479afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TRIGGER IF EXISTS video_cleanup"); 1480afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TRIGGER IF EXISTS audio_playlists_cleanup"); 1481afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("DROP TRIGGER IF EXISTS audio_delete"); 148236339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood 1483afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE TRIGGER IF NOT EXISTS images_cleanup DELETE ON files " + 1484afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "WHEN old.media_type = " + FileColumns.MEDIA_TYPE_IMAGE + " " + 148536339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood "BEGIN " + 1486afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "DELETE FROM thumbnails WHERE image_id = old._id;" + 1487afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "SELECT _DELETE_FILE(old._data);" + 148836339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood "END"); 148936339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood 1490afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE TRIGGER IF NOT EXISTS video_cleanup DELETE ON files " + 149149dea76284f7693ba452c05cfd59c1d9c9584343Ray Chen "WHEN old.media_type = " + FileColumns.MEDIA_TYPE_VIDEO + " " + 149236339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood "BEGIN " + 1493afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "SELECT _DELETE_FILE(old._data);" + 149436339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood "END"); 149536339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood 1496afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (!internal) { 1497afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE TRIGGER IF NOT EXISTS audio_meta_cleanup DELETE ON files " + 1498afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "WHEN old.media_type = " + FileColumns.MEDIA_TYPE_AUDIO + " " + 1499afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "BEGIN " + 1500afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "DELETE FROM audio_genres_map WHERE audio_id = old._id;" + 1501afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "DELETE FROM audio_playlists_map WHERE audio_id = old._id;" + 1502afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "END"); 1503afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1504afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE TRIGGER IF NOT EXISTS audio_playlists_cleanup DELETE ON files " + 1505afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "WHEN old.media_type = " + FileColumns.MEDIA_TYPE_PLAYLIST + " " + 1506afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "BEGIN " + 1507afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "DELETE FROM audio_playlists_map WHERE playlist_id = old._id;" + 1508afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "SELECT _DELETE_FILE(old._data);" + 1509afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "END"); 1510afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 1511afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood db.execSQL("CREATE TRIGGER IF NOT EXISTS audio_delete INSTEAD OF DELETE ON audio " + 151236339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood "BEGIN " + 1513afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "DELETE from files where _id=old._id;" + 1514afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "DELETE from audio_playlists_map where audio_id=old._id;" + 1515afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "DELETE from audio_genres_map where audio_id=old._id;" + 151636339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood "END"); 151736339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood } 151836339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood } 151936339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood 1520db8357b2b2888ce3778278e9cd9e698347ca6105Owen Lin if (fromVersion < 301) { 1521db8357b2b2888ce3778278e9cd9e698347ca6105Owen Lin db.execSQL("DROP INDEX IF EXISTS bucket_index"); 1522db8357b2b2888ce3778278e9cd9e698347ca6105Owen Lin db.execSQL("CREATE INDEX bucket_index on files(bucket_id, media_type, datetaken, _id)"); 1523db8357b2b2888ce3778278e9cd9e698347ca6105Owen Lin db.execSQL("CREATE INDEX bucket_name on files(bucket_id, media_type, bucket_display_name)"); 1524db8357b2b2888ce3778278e9cd9e698347ca6105Owen Lin } 1525db8357b2b2888ce3778278e9cd9e698347ca6105Owen Lin 152620405fab4cf752dbdec6f1020bfc70a2bf87590eMike Lockwood if (fromVersion < 302) { 152720405fab4cf752dbdec6f1020bfc70a2bf87590eMike Lockwood db.execSQL("CREATE INDEX parent_index ON files(parent);"); 152820405fab4cf752dbdec6f1020bfc70a2bf87590eMike Lockwood db.execSQL("CREATE INDEX format_index ON files(format);"); 152920405fab4cf752dbdec6f1020bfc70a2bf87590eMike Lockwood } 153020405fab4cf752dbdec6f1020bfc70a2bf87590eMike Lockwood 15312658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen if (fromVersion < 303) { 15322658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen // the album disambiguator hash changed, so rescan songs and force 15332658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen // albums to be updated. Artists are unaffected. 15342658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen db.execSQL("DELETE from albums"); 15352658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen db.execSQL("UPDATE files SET date_modified=0 WHERE " + FileColumns.MEDIA_TYPE + "=" 15362658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen + FileColumns.MEDIA_TYPE_AUDIO + ";"); 15372658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen } 15382658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen 15394b5963f15c1563c613ec505ca7962f93aec44321Mike Lockwood if (fromVersion < 304 && !internal) { 154051d6c5d233f78de2db9b3f63514b20b1ce768dd5Mike Lockwood // notifies host when files are deleted 154151d6c5d233f78de2db9b3f63514b20b1ce768dd5Mike Lockwood db.execSQL("CREATE TRIGGER IF NOT EXISTS files_cleanup DELETE ON files " + 154251d6c5d233f78de2db9b3f63514b20b1ce768dd5Mike Lockwood "BEGIN " + 154351d6c5d233f78de2db9b3f63514b20b1ce768dd5Mike Lockwood "SELECT _OBJECT_REMOVED(old._id);" + 154451d6c5d233f78de2db9b3f63514b20b1ce768dd5Mike Lockwood "END"); 154551d6c5d233f78de2db9b3f63514b20b1ce768dd5Mike Lockwood 154651d6c5d233f78de2db9b3f63514b20b1ce768dd5Mike Lockwood } 154751d6c5d233f78de2db9b3f63514b20b1ce768dd5Mike Lockwood 15484b5963f15c1563c613ec505ca7962f93aec44321Mike Lockwood if (fromVersion < 305 && internal) { 15494b5963f15c1563c613ec505ca7962f93aec44321Mike Lockwood // version 304 erroneously added this trigger to the internal database 15504b5963f15c1563c613ec505ca7962f93aec44321Mike Lockwood db.execSQL("DROP TRIGGER IF EXISTS files_cleanup"); 15514b5963f15c1563c613ec505ca7962f93aec44321Mike Lockwood } 15524b5963f15c1563c613ec505ca7962f93aec44321Mike Lockwood 1553fda522dc66b94057f9c6676cb8ba10bc3b13daeaMarco Nelissen if (fromVersion < 306 && !internal) { 1554efe0bcdf5ed215a5cb76c8a48aad1333056636f4Marco Nelissen // The genre list was expanded and genre string parsing was tweaked, so 1555efe0bcdf5ed215a5cb76c8a48aad1333056636f4Marco Nelissen // rebuild the genre list 1556efe0bcdf5ed215a5cb76c8a48aad1333056636f4Marco Nelissen db.execSQL("UPDATE files SET date_modified=0 WHERE " + FileColumns.MEDIA_TYPE + "=" 1557efe0bcdf5ed215a5cb76c8a48aad1333056636f4Marco Nelissen + FileColumns.MEDIA_TYPE_AUDIO + ";"); 1558efe0bcdf5ed215a5cb76c8a48aad1333056636f4Marco Nelissen db.execSQL("DELETE FROM audio_genres_map"); 1559efe0bcdf5ed215a5cb76c8a48aad1333056636f4Marco Nelissen db.execSQL("DELETE FROM audio_genres"); 1560efe0bcdf5ed215a5cb76c8a48aad1333056636f4Marco Nelissen } 1561efe0bcdf5ed215a5cb76c8a48aad1333056636f4Marco Nelissen 156265587f9c204abb2d179527dfdca009f4780e9743Ray Chen if (fromVersion < 307 && !internal) { 156365587f9c204abb2d179527dfdca009f4780e9743Ray Chen // Force rescan of image entries to update DATE_TAKEN by either GPSTimeStamp or 156465587f9c204abb2d179527dfdca009f4780e9743Ray Chen // EXIF local time. 156565587f9c204abb2d179527dfdca009f4780e9743Ray Chen db.execSQL("UPDATE files SET date_modified=0 WHERE " + FileColumns.MEDIA_TYPE + "=" 156665587f9c204abb2d179527dfdca009f4780e9743Ray Chen + FileColumns.MEDIA_TYPE_IMAGE + ";"); 156765587f9c204abb2d179527dfdca009f4780e9743Ray Chen } 156865587f9c204abb2d179527dfdca009f4780e9743Ray Chen 15694f63f7c1e6f602a77abd43b189f296b9eb36635bMike Lockwood // Database version 401 did not add storage_id to the internal database. 15704f63f7c1e6f602a77abd43b189f296b9eb36635bMike Lockwood // We need it there too, so add it in version 402 15714f63f7c1e6f602a77abd43b189f296b9eb36635bMike Lockwood if (fromVersion < 401 || (fromVersion == 401 && internal)) { 15729be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood // Add column for MTP storage ID 15739be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood db.execSQL("ALTER TABLE files ADD COLUMN storage_id INTEGER;"); 15749be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood // Anything in the database before this upgrade step will be in the primary storage 15759be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood db.execSQL("UPDATE files SET storage_id=" + MtpStorage.getStorageId(0) + ";"); 15769be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood } 15779be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood 157878b2885edc406273d688536b0eadfea006b20662Marco Nelissen if (fromVersion < 403 && !internal) { 157978b2885edc406273d688536b0eadfea006b20662Marco Nelissen db.execSQL("CREATE VIEW audio_genres_map_noid AS " + 158078b2885edc406273d688536b0eadfea006b20662Marco Nelissen "SELECT audio_id,genre_id from audio_genres_map;"); 158178b2885edc406273d688536b0eadfea006b20662Marco Nelissen } 158278b2885edc406273d688536b0eadfea006b20662Marco Nelissen 15839289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen if (fromVersion < 404) { 15849289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen // There was a bug that could cause distinct same-named albums to be 15859289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen // combined again. Delete albums and force a rescan. 15869289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen db.execSQL("DELETE from albums"); 15879289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen db.execSQL("UPDATE files SET date_modified=0 WHERE " + FileColumns.MEDIA_TYPE + "=" 15889289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen + FileColumns.MEDIA_TYPE_AUDIO + ";"); 15899289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen } 15909289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen 1591957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang if (fromVersion < 405) { 1592957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang // Add is_drm column. 1593957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang db.execSQL("ALTER TABLE files ADD COLUMN is_drm INTEGER;"); 1594957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang 1595957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang db.execSQL("DROP VIEW IF EXISTS audio_meta"); 1596957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang db.execSQL("CREATE VIEW audio_meta AS SELECT _id," + AUDIO_COLUMNSv405 + 1597957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang " FROM files WHERE " + FileColumns.MEDIA_TYPE + "=" 1598957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang + FileColumns.MEDIA_TYPE_AUDIO + ";"); 1599957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang 1600957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang recreateAudioView(db); 1601957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang } 1602957002d42eec79c6f7ce11c98483d7aa3f224e51Gloria Wang 1603b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood if (fromVersion < 407) { 16047ee82723c70fc02b168cfa9b6ff7d5fdd0c16d53Gloria Wang // Rescan files in the media database because a new column has been added 1605b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood // in table files in version 405 and to recover from problems populating 1606b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood // the genre tables 16077ee82723c70fc02b168cfa9b6ff7d5fdd0c16d53Gloria Wang db.execSQL("UPDATE files SET date_modified=0;"); 16087ee82723c70fc02b168cfa9b6ff7d5fdd0c16d53Gloria Wang } 16097ee82723c70fc02b168cfa9b6ff7d5fdd0c16d53Gloria Wang 1610bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang if (fromVersion < 408) { 1611bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang // Add the width/height columns for images and video 1612bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang db.execSQL("ALTER TABLE files ADD COLUMN width INTEGER;"); 1613bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang db.execSQL("ALTER TABLE files ADD COLUMN height INTEGER;"); 1614bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang 1615bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang // Rescan files to fill the columns 1616bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang db.execSQL("UPDATE files SET date_modified=0;"); 1617bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang 1618bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang // Update images and video views to contain the width/height columns 1619bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang db.execSQL("DROP VIEW IF EXISTS images"); 1620bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang db.execSQL("DROP VIEW IF EXISTS video"); 1621bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang db.execSQL("CREATE VIEW images AS SELECT _id," + IMAGE_COLUMNS + 1622bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang " FROM files WHERE " + FileColumns.MEDIA_TYPE + "=" 1623bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang + FileColumns.MEDIA_TYPE_IMAGE + ";"); 1624bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang db.execSQL("CREATE VIEW video AS SELECT _id," + VIDEO_COLUMNS + 1625bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang " FROM files WHERE " + FileColumns.MEDIA_TYPE + "=" 1626bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang + FileColumns.MEDIA_TYPE_VIDEO + ";"); 1627bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang } 1628bdcd6c157b84f26bd006188c18c8c07a543afe8cChih-Chung Chang 16295809eb2b5fd77bd7d14548669c70e4a672e43df6Marco Nelissen if (fromVersion < 409 && !internal) { 16305809eb2b5fd77bd7d14548669c70e4a672e43df6Marco Nelissen // A bug that prevented numeric genres from being parsed was fixed, so 16315809eb2b5fd77bd7d14548669c70e4a672e43df6Marco Nelissen // rebuild the genre list 16325809eb2b5fd77bd7d14548669c70e4a672e43df6Marco Nelissen db.execSQL("UPDATE files SET date_modified=0 WHERE " + FileColumns.MEDIA_TYPE + "=" 16335809eb2b5fd77bd7d14548669c70e4a672e43df6Marco Nelissen + FileColumns.MEDIA_TYPE_AUDIO + ";"); 16345809eb2b5fd77bd7d14548669c70e4a672e43df6Marco Nelissen db.execSQL("DELETE FROM audio_genres_map"); 16355809eb2b5fd77bd7d14548669c70e4a672e43df6Marco Nelissen db.execSQL("DELETE FROM audio_genres"); 16365809eb2b5fd77bd7d14548669c70e4a672e43df6Marco Nelissen } 16375809eb2b5fd77bd7d14548669c70e4a672e43df6Marco Nelissen 1638166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen if (fromVersion < 500) { 1639166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen // we're now deleting the file in mediaprovider code, rather than via a trigger 1640166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen db.execSQL("DROP TRIGGER IF EXISTS videothumbnails_cleanup;"); 1641166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen } 1642a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen if (fromVersion < 501) { 1643a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen // we're now deleting the file in mediaprovider code, rather than via a trigger 1644a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen // the images_cleanup trigger would delete the image file and the entry 1645a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen // in the thumbnail table, which in turn would trigger thumbnails_cleanup 1646a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen // to delete the thumbnail image 1647a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen db.execSQL("DROP TRIGGER IF EXISTS images_cleanup;"); 1648a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen db.execSQL("DROP TRIGGER IF EXISTS thumbnails_cleanup;"); 1649a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen } 16505afff430a4ebb751dadeb0112a1fe2052c6f5c05Marco Nelissen if (fromVersion < 502) { 16515afff430a4ebb751dadeb0112a1fe2052c6f5c05Marco Nelissen // we're now deleting the file in mediaprovider code, rather than via a trigger 16525afff430a4ebb751dadeb0112a1fe2052c6f5c05Marco Nelissen db.execSQL("DROP TRIGGER IF EXISTS video_cleanup;"); 16535afff430a4ebb751dadeb0112a1fe2052c6f5c05Marco Nelissen } 16545118dba282c95fda77e03e63b6dd11505c474ee5Marco Nelissen if (fromVersion < 503) { 16555118dba282c95fda77e03e63b6dd11505c474ee5Marco Nelissen // genre and playlist cleanup now done in mediaprovider code, instead of in a trigger 16565118dba282c95fda77e03e63b6dd11505c474ee5Marco Nelissen db.execSQL("DROP TRIGGER IF EXISTS audio_delete"); 16575118dba282c95fda77e03e63b6dd11505c474ee5Marco Nelissen db.execSQL("DROP TRIGGER IF EXISTS audio_meta_cleanup"); 16585118dba282c95fda77e03e63b6dd11505c474ee5Marco Nelissen } 165990c7da0610b7c3f4d9f4f3b2767e0bae5f3ab258Marco Nelissen if (fromVersion < 504) { 166090c7da0610b7c3f4d9f4f3b2767e0bae5f3ab258Marco Nelissen // add an index to help with case-insensitive matching of paths 166190c7da0610b7c3f4d9f4f3b2767e0bae5f3ab258Marco Nelissen db.execSQL( 166290c7da0610b7c3f4d9f4f3b2767e0bae5f3ab258Marco Nelissen "CREATE INDEX IF NOT EXISTS path_index_lower ON files(_data COLLATE NOCASE);"); 166390c7da0610b7c3f4d9f4f3b2767e0bae5f3ab258Marco Nelissen } 16647074cb9b72666fc300605abe5fa4d28f7f9f4c0dMarco Nelissen if (fromVersion < 505) { 16657074cb9b72666fc300605abe5fa4d28f7f9f4c0dMarco Nelissen // Starting with schema 505 we fill in the width/height/resolution columns for videos, 16667074cb9b72666fc300605abe5fa4d28f7f9f4c0dMarco Nelissen // so force a rescan of videos to fill in the blanks 16677074cb9b72666fc300605abe5fa4d28f7f9f4c0dMarco Nelissen db.execSQL("UPDATE files SET date_modified=0 WHERE " + FileColumns.MEDIA_TYPE + "=" 16687074cb9b72666fc300605abe5fa4d28f7f9f4c0dMarco Nelissen + FileColumns.MEDIA_TYPE_VIDEO + ";"); 16697074cb9b72666fc300605abe5fa4d28f7f9f4c0dMarco Nelissen } 167059f8f11eaef252b82d62bfd5e763ccf350aa48b6Marco Nelissen if (fromVersion < 506) { 167159f8f11eaef252b82d62bfd5e763ccf350aa48b6Marco Nelissen // sd card storage got moved to /storage/sdcard0 167259f8f11eaef252b82d62bfd5e763ccf350aa48b6Marco Nelissen // first delete everything that already got scanned in /storage before this 167359f8f11eaef252b82d62bfd5e763ccf350aa48b6Marco Nelissen // update step was added 167459f8f11eaef252b82d62bfd5e763ccf350aa48b6Marco Nelissen db.execSQL("DROP TRIGGER IF EXISTS files_cleanup"); 167559f8f11eaef252b82d62bfd5e763ccf350aa48b6Marco Nelissen db.execSQL("DELETE FROM files WHERE _data LIKE '/storage/%';"); 167659f8f11eaef252b82d62bfd5e763ccf350aa48b6Marco Nelissen db.execSQL("DELETE FROM album_art WHERE _data LIKE '/storage/%';"); 167759f8f11eaef252b82d62bfd5e763ccf350aa48b6Marco Nelissen db.execSQL("DELETE FROM thumbnails WHERE _data LIKE '/storage/%';"); 167859f8f11eaef252b82d62bfd5e763ccf350aa48b6Marco Nelissen db.execSQL("DELETE FROM videothumbnails WHERE _data LIKE '/storage/%';"); 167959f8f11eaef252b82d62bfd5e763ccf350aa48b6Marco Nelissen // then rename everything from /mnt/sdcard/ to /storage/sdcard0, 168059f8f11eaef252b82d62bfd5e763ccf350aa48b6Marco Nelissen // and from /mnt/external1 to /storage/sdcard1 168159f8f11eaef252b82d62bfd5e763ccf350aa48b6Marco Nelissen db.execSQL("UPDATE files SET " + 168259f8f11eaef252b82d62bfd5e763ccf350aa48b6Marco Nelissen "_data='/storage/sdcard0'||SUBSTR(_data,12) WHERE _data LIKE '/mnt/sdcard/%';"); 168359f8f11eaef252b82d62bfd5e763ccf350aa48b6Marco Nelissen db.execSQL("UPDATE files SET " + 168459f8f11eaef252b82d62bfd5e763ccf350aa48b6Marco Nelissen "_data='/storage/sdcard1'||SUBSTR(_data,15) WHERE _data LIKE '/mnt/external1/%';"); 168559f8f11eaef252b82d62bfd5e763ccf350aa48b6Marco Nelissen db.execSQL("UPDATE album_art SET " + 168659f8f11eaef252b82d62bfd5e763ccf350aa48b6Marco Nelissen "_data='/storage/sdcard0'||SUBSTR(_data,12) WHERE _data LIKE '/mnt/sdcard/%';"); 168759f8f11eaef252b82d62bfd5e763ccf350aa48b6Marco Nelissen db.execSQL("UPDATE album_art SET " + 168859f8f11eaef252b82d62bfd5e763ccf350aa48b6Marco Nelissen "_data='/storage/sdcard1'||SUBSTR(_data,15) WHERE _data LIKE '/mnt/external1/%';"); 168959f8f11eaef252b82d62bfd5e763ccf350aa48b6Marco Nelissen db.execSQL("UPDATE thumbnails SET " + 169059f8f11eaef252b82d62bfd5e763ccf350aa48b6Marco Nelissen "_data='/storage/sdcard0'||SUBSTR(_data,12) WHERE _data LIKE '/mnt/sdcard/%';"); 169159f8f11eaef252b82d62bfd5e763ccf350aa48b6Marco Nelissen db.execSQL("UPDATE thumbnails SET " + 169259f8f11eaef252b82d62bfd5e763ccf350aa48b6Marco Nelissen "_data='/storage/sdcard1'||SUBSTR(_data,15) WHERE _data LIKE '/mnt/external1/%';"); 169359f8f11eaef252b82d62bfd5e763ccf350aa48b6Marco Nelissen db.execSQL("UPDATE videothumbnails SET " + 169459f8f11eaef252b82d62bfd5e763ccf350aa48b6Marco Nelissen "_data='/storage/sdcard0'||SUBSTR(_data,12) WHERE _data LIKE '/mnt/sdcard/%';"); 169559f8f11eaef252b82d62bfd5e763ccf350aa48b6Marco Nelissen db.execSQL("UPDATE videothumbnails SET " + 169659f8f11eaef252b82d62bfd5e763ccf350aa48b6Marco Nelissen "_data='/storage/sdcard1'||SUBSTR(_data,15) WHERE _data LIKE '/mnt/external1/%';"); 169759f8f11eaef252b82d62bfd5e763ccf350aa48b6Marco Nelissen 169859f8f11eaef252b82d62bfd5e763ccf350aa48b6Marco Nelissen if (!internal) { 169959f8f11eaef252b82d62bfd5e763ccf350aa48b6Marco Nelissen db.execSQL("CREATE TRIGGER IF NOT EXISTS files_cleanup DELETE ON files " + 170059f8f11eaef252b82d62bfd5e763ccf350aa48b6Marco Nelissen "BEGIN " + 170159f8f11eaef252b82d62bfd5e763ccf350aa48b6Marco Nelissen "SELECT _OBJECT_REMOVED(old._id);" + 170259f8f11eaef252b82d62bfd5e763ccf350aa48b6Marco Nelissen "END"); 170359f8f11eaef252b82d62bfd5e763ccf350aa48b6Marco Nelissen } 170459f8f11eaef252b82d62bfd5e763ccf350aa48b6Marco Nelissen } 1705a2466a7a8613b61fa570a4e68bff9460c1ab1920Owen Lin if (fromVersion < 507) { 1706a2466a7a8613b61fa570a4e68bff9460c1ab1920Owen Lin // we update _data in version 506, we need to update the bucket_id as well 1707677d5c9a353fd956c9cb981ca38d9fb351c0421dMarco Nelissen updateBucketNames(db); 1708a2466a7a8613b61fa570a4e68bff9460c1ab1920Owen Lin } 170946e56db35b1ac30062db31f38b04cb719bba6bd8Marco Nelissen if (fromVersion < 508 && !internal) { 171046e56db35b1ac30062db31f38b04cb719bba6bd8Marco Nelissen // ensure we don't get duplicate entries in the genre map 171146e56db35b1ac30062db31f38b04cb719bba6bd8Marco Nelissen db.execSQL("CREATE TABLE IF NOT EXISTS audio_genres_map_tmp (" + 171246e56db35b1ac30062db31f38b04cb719bba6bd8Marco Nelissen "_id INTEGER PRIMARY KEY," + 171346e56db35b1ac30062db31f38b04cb719bba6bd8Marco Nelissen "audio_id INTEGER NOT NULL," + 171446e56db35b1ac30062db31f38b04cb719bba6bd8Marco Nelissen "genre_id INTEGER NOT NULL," + 171546e56db35b1ac30062db31f38b04cb719bba6bd8Marco Nelissen "UNIQUE (audio_id,genre_id) ON CONFLICT IGNORE" + 171646e56db35b1ac30062db31f38b04cb719bba6bd8Marco Nelissen ");"); 171746e56db35b1ac30062db31f38b04cb719bba6bd8Marco Nelissen db.execSQL("INSERT INTO audio_genres_map_tmp (audio_id,genre_id)" + 171846e56db35b1ac30062db31f38b04cb719bba6bd8Marco Nelissen " SELECT DISTINCT audio_id,genre_id FROM audio_genres_map;"); 171946e56db35b1ac30062db31f38b04cb719bba6bd8Marco Nelissen db.execSQL("DROP TABLE audio_genres_map;"); 172046e56db35b1ac30062db31f38b04cb719bba6bd8Marco Nelissen db.execSQL("ALTER TABLE audio_genres_map_tmp RENAME TO audio_genres_map;"); 172146e56db35b1ac30062db31f38b04cb719bba6bd8Marco Nelissen } 1722988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen 1723988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen if (fromVersion < 509) { 1724988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen db.execSQL("CREATE TABLE IF NOT EXISTS log (time DATETIME PRIMARY KEY, message TEXT);"); 1725988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen } 1726acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen sanityCheck(db, fromVersion); 1727988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen long elapsedSeconds = (SystemClock.currentTimeMicro() - startTime) / 1000000; 1728988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen logToDb(db, "Database upgraded from version " + fromVersion + " to " + toVersion 1729988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen + " in " + elapsedSeconds + " seconds"); 1730988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen } 1731988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen 1732988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen /** 1733988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen * Write a persistent diagnostic message to the log table. 1734988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen */ 1735988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen static void logToDb(SQLiteDatabase db, String message) { 1736988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen db.execSQL("INSERT INTO log (time, message) VALUES (datetime('now'),?);", 1737988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen new String[] { message }); 1738988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen // delete all but the last 500 rows 1739988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen db.execSQL("DELETE FROM log WHERE rowid IN" + 1740988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen " (SELECT rowid FROM log ORDER BY time DESC LIMIT 500,-1);"); 17411d4a8ec9e1e62427088dc40f08872a10c863535eMarco Nelissen } 17421d4a8ec9e1e62427088dc40f08872a10c863535eMarco Nelissen 17431d4a8ec9e1e62427088dc40f08872a10c863535eMarco Nelissen /** 1744216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen * Perform a simple sanity check on the database. Currently this tests 1745216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen * whether all the _data entries in audio_meta are unique 1746216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen */ 1747216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen private static void sanityCheck(SQLiteDatabase db, int fromVersion) { 1748216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen Cursor c1 = db.query("audio_meta", new String[] {"count(*)"}, 1749216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen null, null, null, null, null); 1750216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen Cursor c2 = db.query("audio_meta", new String[] {"count(distinct _data)"}, 1751216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen null, null, null, null, null); 1752216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen c1.moveToFirst(); 1753216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen c2.moveToFirst(); 1754216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen int num1 = c1.getInt(0); 1755216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen int num2 = c2.getInt(0); 1756216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen c1.close(); 1757216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen c2.close(); 1758216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen if (num1 != num2) { 1759216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen Log.e(TAG, "audio_meta._data column is not unique while upgrading" + 1760216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen " from schema " +fromVersion + " : " + num1 +"/" + num2); 1761216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen // Delete all audio_meta rows so they will be rebuilt by the media scanner 1762216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen db.execSQL("DELETE FROM audio_meta;"); 1763216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen } 1764702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1765702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1766702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static void recreateAudioView(SQLiteDatabase db) { 1767702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Provides a unified audio/artist/album info view. 1768702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP VIEW IF EXISTS audio"); 1769702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE VIEW IF NOT EXISTS audio as SELECT * FROM audio_meta " + 1770702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "LEFT OUTER JOIN artists ON audio_meta.artist_id=artists.artist_id " + 1771702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "LEFT OUTER JOIN albums ON audio_meta.album_id=albums.album_id;"); 1772702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 177395ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen 1774702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 1775677d5c9a353fd956c9cb981ca38d9fb351c0421dMarco Nelissen * Update the bucket_id and bucket_display_name columns for images and videos 1776702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param db 1777702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param tableName 1778702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 1779677d5c9a353fd956c9cb981ca38d9fb351c0421dMarco Nelissen private static void updateBucketNames(SQLiteDatabase db) { 1780702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Rebuild the bucket_display_name column using the natural case rather than lower case. 1781702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.beginTransaction(); 1782702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 1783702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String[] columns = {BaseColumns._ID, MediaColumns.DATA}; 1784677d5c9a353fd956c9cb981ca38d9fb351c0421dMarco Nelissen // update only images and videos 1785677d5c9a353fd956c9cb981ca38d9fb351c0421dMarco Nelissen Cursor cursor = db.query("files", columns, "media_type=1 OR media_type=3", 1786677d5c9a353fd956c9cb981ca38d9fb351c0421dMarco Nelissen null, null, null, null); 1787702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 1788702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final int idColumnIndex = cursor.getColumnIndex(BaseColumns._ID); 1789702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final int dataColumnIndex = cursor.getColumnIndex(MediaColumns.DATA); 17909491c3bd011644f5fe69fd47f73d0e1245b33febMarco Nelissen String [] rowId = new String[1]; 1791988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen ContentValues values = new ContentValues(); 1792702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project while (cursor.moveToNext()) { 1793702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String data = cursor.getString(dataColumnIndex); 1794988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen rowId[0] = cursor.getString(idColumnIndex); 1795d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen if (data != null) { 1796988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen values.clear(); 1797d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen computeBucketValues(data, values); 1798677d5c9a353fd956c9cb981ca38d9fb351c0421dMarco Nelissen db.update("files", values, "_id=?", rowId); 1799d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen } else { 1800d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen Log.w(TAG, "null data at id " + rowId); 1801d6dc8dc70ae177c37be1c63ce6ebd97f27c44bd8Marco Nelissen } 1802702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1803702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 1804702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project cursor.close(); 1805702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1806702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.setTransactionSuccessful(); 1807702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 1808702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.endTransaction(); 1809702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1810702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1811702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1812702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 1813702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Iterate through the rows of a table in a database, ensuring that the 1814702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * display name column has a value. 1815702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param db 1816702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param tableName 1817702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 1818702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static void updateDisplayName(SQLiteDatabase db, String tableName) { 1819702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Fill in default values for null displayName values 1820702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.beginTransaction(); 1821702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 1822702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String[] columns = {BaseColumns._ID, MediaColumns.DATA, MediaColumns.DISPLAY_NAME}; 1823702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Cursor cursor = db.query(tableName, columns, null, null, null, null, null); 1824702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 1825702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final int idColumnIndex = cursor.getColumnIndex(BaseColumns._ID); 1826702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final int dataColumnIndex = cursor.getColumnIndex(MediaColumns.DATA); 1827702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final int displayNameIndex = cursor.getColumnIndex(MediaColumns.DISPLAY_NAME); 1828702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(); 1829702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project while (cursor.moveToNext()) { 1830702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String displayName = cursor.getString(displayNameIndex); 1831702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (displayName == null) { 1832702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String data = cursor.getString(dataColumnIndex); 1833702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.clear(); 1834702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project computeDisplayName(data, values); 1835702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int rowId = cursor.getInt(idColumnIndex); 1836702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.update(tableName, values, "_id=" + rowId, null); 1837702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1838702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1839702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 1840702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project cursor.close(); 1841702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1842702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.setTransactionSuccessful(); 1843702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 1844702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.endTransaction(); 1845702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1846702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1847988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen 1848702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 1849702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param data The input path 1850702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param values the content values, where the bucked id name and bucket display name are updated. 1851702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 1852702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 1853702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static void computeBucketValues(String data, ContentValues values) { 1854702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File parentFile = new File(data).getParentFile(); 1855702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (parentFile == null) { 1856702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project parentFile = new File("/"); 1857702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1858702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1859702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Lowercase the path for hashing. This avoids duplicate buckets if the 1860702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // filepath case is changed externally. 1861702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Keep the original case for display. 1862702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String path = parentFile.toString().toLowerCase(); 1863702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String name = parentFile.getName(); 1864702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1865702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Note: the BUCKET_ID and BUCKET_DISPLAY_NAME attributes are spelled the 1866702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // same for both images and video. However, for backwards-compatibility reasons 1867702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // there is no common base class. We use the ImageColumns version here 1868d0d809c65db7d4936266c8f6a18511046c84fd15Mike Lockwood values.put(ImageColumns.BUCKET_ID, path.hashCode()); 1869702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(ImageColumns.BUCKET_DISPLAY_NAME, name); 1870702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1871702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1872702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 1873702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param data The input path 1874702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param values the content values, where the display name is updated. 1875702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 1876702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 1877702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static void computeDisplayName(String data, ContentValues values) { 1878702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String s = (data == null ? "" : data.toString()); 1879702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int idx = s.lastIndexOf('/'); 1880702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (idx >= 0) { 1881702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project s = s.substring(idx + 1); 1882702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1883702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put("_display_name", s); 1884702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1885702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1886b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen /** 1887498b62c2912302a23532c73a028a7684c5df33caRay Chen * Copy taken time from date_modified if we lost the original value (e.g. after factory reset) 1888498b62c2912302a23532c73a028a7684c5df33caRay Chen * This works for both video and image tables. 1889b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen * 1890b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen * @param values the content values, where taken time is updated. 1891b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen */ 1892b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen private static void computeTakenTime(ContentValues values) { 1893b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen if (! values.containsKey(Images.Media.DATE_TAKEN)) { 1894b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen // This only happens when MediaScanner finds an image file that doesn't have any useful 1895b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen // reference to get this value. (e.g. GPSTimeStamp) 1896498b62c2912302a23532c73a028a7684c5df33caRay Chen Long lastModified = values.getAsLong(MediaColumns.DATE_MODIFIED); 1897b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen if (lastModified != null) { 1898b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen values.put(Images.Media.DATE_TAKEN, lastModified * 1000); 1899b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen } 1900b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen } 1901b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen } 1902b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen 1903b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen /** 1904b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen * This method blocks until thumbnail is ready. 1905b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen * 1906b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen * @param thumbUri 1907b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen * @return 1908b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen */ 1909b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private boolean waitForThumbnailReady(Uri origUri) { 1910b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen Cursor c = this.query(origUri, new String[] { ImageColumns._ID, ImageColumns.DATA, 1911b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen ImageColumns.MINI_THUMB_MAGIC}, null, null, null); 1912b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (c == null) return false; 1913b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1914b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen boolean result = false; 1915b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1916b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (c.moveToFirst()) { 1917e263c2a4b880ef8a5314bb4379c74bf5f9292bd0Ray Chen long id = c.getLong(0); 1918b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen String path = c.getString(1); 1919b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen long magic = c.getLong(2); 1920b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 19219299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen MediaThumbRequest req = requestMediaThumbnail(path, origUri, 19229299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen MediaThumbRequest.PRIORITY_HIGH, magic); 19239299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen if (req == null) { 19249299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen return false; 19259299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen } 19269299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen synchronized (req) { 19279299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen try { 19289299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen while (req.mState == MediaThumbRequest.State.WAIT) { 19299299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen req.wait(); 193020434e032e498b716f87cce2f23dd646819218bfRay Chen } 19319299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen } catch (InterruptedException e) { 19329299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen Log.w(TAG, e); 19339299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen } 19349299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen if (req.mState == MediaThumbRequest.State.DONE) { 19359299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen result = true; 1936b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1937b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1938b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1939b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen c.close(); 1940b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1941b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return result; 1942b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1943b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1944e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen private boolean matchThumbRequest(MediaThumbRequest req, int pid, long id, long gid, 1945e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen boolean isVideo) { 1946e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen boolean cancelAllOrigId = (id == -1); 1947e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen boolean cancelAllGroupId = (gid == -1); 1948e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen return (req.mCallingPid == pid) && 1949e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen (cancelAllGroupId || req.mGroupId == gid) && 1950e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen (cancelAllOrigId || req.mOrigId == id) && 1951e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen (req.mIsVideo == isVideo); 1952e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen } 1953e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen 1954b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private boolean queryThumbnail(SQLiteQueryBuilder qb, Uri uri, String table, 1955b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen String column, boolean hasThumbnailId) { 1956b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen qb.setTables(table); 1957b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (hasThumbnailId) { 1958b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // For uri dispatched to this method, the 4th path segment is always 1959b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // the thumbnail id. 1960b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen qb.appendWhere("_id = " + uri.getPathSegments().get(3)); 1961b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // client already knows which thumbnail it wants, bypass it. 1962b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return true; 1963b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1964b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen String origId = uri.getQueryParameter("orig_id"); 1965b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // We can't query ready_flag unless we know original id 1966b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (origId == null) { 1967b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // this could be thumbnail query for other purpose, bypass it. 1968b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return true; 1969b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1970b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1971b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen boolean needBlocking = "1".equals(uri.getQueryParameter("blocking")); 197220434e032e498b716f87cce2f23dd646819218bfRay Chen boolean cancelRequest = "1".equals(uri.getQueryParameter("cancel")); 1973e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen Uri origUri = uri.buildUpon().encodedPath( 1974e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen uri.getPath().replaceFirst("thumbnails", "media")) 1975e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen .appendPath(origId).build(); 1976b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1977b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (needBlocking && !waitForThumbnailReady(origUri)) { 197820434e032e498b716f87cce2f23dd646819218bfRay Chen Log.w(TAG, "original media doesn't exist or it's canceled."); 1979b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return false; 198020434e032e498b716f87cce2f23dd646819218bfRay Chen } else if (cancelRequest) { 1981e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen String groupId = uri.getQueryParameter("group_id"); 1982e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen boolean isVideo = "video".equals(uri.getPathSegments().get(1)); 198320434e032e498b716f87cce2f23dd646819218bfRay Chen int pid = Binder.getCallingPid(); 198420434e032e498b716f87cce2f23dd646819218bfRay Chen long id = -1; 1985e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen long gid = -1; 1986e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen 198720434e032e498b716f87cce2f23dd646819218bfRay Chen try { 198820434e032e498b716f87cce2f23dd646819218bfRay Chen id = Long.parseLong(origId); 1989e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen gid = Long.parseLong(groupId); 199020434e032e498b716f87cce2f23dd646819218bfRay Chen } catch (NumberFormatException ex) { 199120434e032e498b716f87cce2f23dd646819218bfRay Chen // invalid cancel request 199220434e032e498b716f87cce2f23dd646819218bfRay Chen return false; 199320434e032e498b716f87cce2f23dd646819218bfRay Chen } 1994e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen 199520434e032e498b716f87cce2f23dd646819218bfRay Chen synchronized (mMediaThumbQueue) { 1996e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen if (mCurrentThumbRequest != null && 1997e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen matchThumbRequest(mCurrentThumbRequest, pid, id, gid, isVideo)) { 199820434e032e498b716f87cce2f23dd646819218bfRay Chen synchronized (mCurrentThumbRequest) { 199920434e032e498b716f87cce2f23dd646819218bfRay Chen mCurrentThumbRequest.mState = MediaThumbRequest.State.CANCEL; 200020434e032e498b716f87cce2f23dd646819218bfRay Chen mCurrentThumbRequest.notifyAll(); 200120434e032e498b716f87cce2f23dd646819218bfRay Chen } 200220434e032e498b716f87cce2f23dd646819218bfRay Chen } 200320434e032e498b716f87cce2f23dd646819218bfRay Chen for (MediaThumbRequest mtq : mMediaThumbQueue) { 2004e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen if (matchThumbRequest(mtq, pid, id, gid, isVideo)) { 200520434e032e498b716f87cce2f23dd646819218bfRay Chen synchronized (mtq) { 200620434e032e498b716f87cce2f23dd646819218bfRay Chen mtq.mState = MediaThumbRequest.State.CANCEL; 200720434e032e498b716f87cce2f23dd646819218bfRay Chen mtq.notifyAll(); 200820434e032e498b716f87cce2f23dd646819218bfRay Chen } 200920434e032e498b716f87cce2f23dd646819218bfRay Chen 201020434e032e498b716f87cce2f23dd646819218bfRay Chen mMediaThumbQueue.remove(mtq); 201120434e032e498b716f87cce2f23dd646819218bfRay Chen } 201220434e032e498b716f87cce2f23dd646819218bfRay Chen } 201320434e032e498b716f87cce2f23dd646819218bfRay Chen } 2014b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 2015b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 2016b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (origId != null) { 2017b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen qb.appendWhere(column + " = " + origId); 2018b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 2019b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return true; 2020b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 2021b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen @SuppressWarnings("fallthrough") 2022702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 2023702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public Cursor query(Uri uri, String[] projectionIn, String selection, 2024702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String[] selectionArgs, String sort) { 2025702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int table = URI_MATCHER.match(uri); 2026baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen List<String> prependArgs = new ArrayList<String>(); 2027702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 202801a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen // Log.v(TAG, "query: uri="+uri+", selection="+selection); 2029702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // handle MEDIA_SCANNER before calling getDatabaseForUri() 2030702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (table == MEDIA_SCANNER) { 2031702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (mMediaScannerVolume == null) { 2032702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return null; 2033702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 2034702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // create a cursor to return volume currently being scanned by the media scanner 20350027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen MatrixCursor c = new MatrixCursor(new String[] {MediaStore.MEDIA_SCANNER_VOLUME}); 20360027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen c.addRow(new String[] {mMediaScannerVolume}); 20370027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen return c; 2038702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2039702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2040702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 20410027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen // Used temporarily (until we have unique media IDs) to get an identifier 20420027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen // for the current sd card, so that the music app doesn't have to use the 20430027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen // non-public getFatVolumeId method 20440027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen if (table == FS_ID) { 20450027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen MatrixCursor c = new MatrixCursor(new String[] {"fsid"}); 20460027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen c.addRow(new Integer[] {mVolumeId}); 20470027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen return c; 20480027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen } 20490027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen 2050704a8b507b7aa61a09457075ed6f80c95914d731Marco Nelissen if (table == VERSION) { 2051704a8b507b7aa61a09457075ed6f80c95914d731Marco Nelissen MatrixCursor c = new MatrixCursor(new String[] {"version"}); 205290c7da0610b7c3f4d9f4f3b2767e0bae5f3ab258Marco Nelissen c.addRow(new Integer[] {getDatabaseVersion(getContext())}); 2053704a8b507b7aa61a09457075ed6f80c95914d731Marco Nelissen return c; 2054704a8b507b7aa61a09457075ed6f80c95914d731Marco Nelissen } 2055704a8b507b7aa61a09457075ed6f80c95914d731Marco Nelissen 2056702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String groupBy = null; 205710af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen DatabaseHelper helper = getDatabaseForUri(uri); 205810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen if (helper == null) { 2059702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return null; 2060702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 206110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumQueries++; 206210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen SQLiteDatabase db = helper.getReadableDatabase(); 20635fde670987a55d69442566dcbdb7830d5f1587c6Chih-Chung Chang if (db == null) return null; 2064702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 20654574e03055af60fada50481f2b34e19a687d5866Marco Nelissen String limit = uri.getQueryParameter("limit"); 2066c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen String filter = uri.getQueryParameter("filter"); 2067c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen String [] keywords = null; 2068c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen if (filter != null) { 2069c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen filter = Uri.decode(filter).trim(); 2070c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen if (!TextUtils.isEmpty(filter)) { 2071c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen String [] searchWords = filter.split(" "); 2072c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen keywords = new String[searchWords.length]; 2073c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen Collator col = Collator.getInstance(); 2074c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen col.setStrength(Collator.PRIMARY); 2075c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen for (int i = 0; i < searchWords.length; i++) { 2076c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen String key = MediaStore.Audio.keyFor(searchWords[i]); 2077c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen key = key.replace("\\", "\\\\"); 2078c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen key = key.replace("%", "\\%"); 2079c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen key = key.replace("_", "\\_"); 2080c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen keywords[i] = key; 2081c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen } 2082c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen } 2083c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen } 2084db8357b2b2888ce3778278e9cd9e698347ca6105Owen Lin if (uri.getQueryParameter("distinct") != null) { 2085db8357b2b2888ce3778278e9cd9e698347ca6105Owen Lin qb.setDistinct(true); 2086db8357b2b2888ce3778278e9cd9e698347ca6105Owen Lin } 2087c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen 2088b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen boolean hasThumbnailId = false; 2089702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2090702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (table) { 2091702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA: 2092702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("images"); 2093702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (uri.getQueryParameter("distinct") != null) 2094702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setDistinct(true); 2095702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2096702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // set the project map so that data dir is prepended to _data. 2097702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project //qb.setProjectionMap(mImagesProjectionMap, true); 2098702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2099702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2100702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA_ID: 2101702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("images"); 2102702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (uri.getQueryParameter("distinct") != null) 2103702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setDistinct(true); 2104702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2105702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // set the project map so that data dir is prepended to _data. 2106702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project //qb.setProjectionMap(mImagesProjectionMap, true); 2107baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen qb.appendWhere("_id=?"); 2108baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(3)); 2109702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2110702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2111702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_THUMBNAILS_ID: 2112b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen hasThumbnailId = true; 2113b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case IMAGES_THUMBNAILS: 2114b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (!queryThumbnail(qb, uri, "thumbnails", "image_id", hasThumbnailId)) { 2115b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return null; 2116b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 2117702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2118702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2119702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA: 2120d9672f4d28ab9038333a0037fe30e386ac0ce610Marco Nelissen if (projectionIn != null && projectionIn.length == 1 && selectionArgs == null 2121ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen && (selection == null || selection.equalsIgnoreCase("is_music=1") 2122ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen || selection.equalsIgnoreCase("is_podcast=1") ) 2123c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen && projectionIn[0].equalsIgnoreCase("count(*)") 2124c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen && keywords != null) { 2125ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen //Log.i("@@@@", "taking fast path for counting songs"); 2126ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.setTables("audio_meta"); 2127ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen } else { 2128ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.setTables("audio"); 2129c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen for (int i = 0; keywords != null && i < keywords.length; i++) { 2130c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen if (i > 0) { 2131c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen qb.appendWhere(" AND "); 2132c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen } 2133c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen qb.appendWhere(MediaStore.Audio.Media.ARTIST_KEY + 2134c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen "||" + MediaStore.Audio.Media.ALBUM_KEY + 2135baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen "||" + MediaStore.Audio.Media.TITLE_KEY + " LIKE ? ESCAPE '\\'"); 2136baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add("%" + keywords[i] + "%"); 2137c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen } 2138ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen } 2139702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2140702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2141702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID: 2142702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio"); 2143baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen qb.appendWhere("_id=?"); 2144baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(3)); 2145702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2146702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2147702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES: 2148702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_genres"); 2149702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id IN (SELECT genre_id FROM " + 2150baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen "audio_genres_map WHERE audio_id=?)"); 2151baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(3)); 2152702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2153702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2154702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES_ID: 2155702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_genres"); 2156baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen qb.appendWhere("_id=?"); 2157baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(5)); 2158702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2159702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2160702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS: 2161702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_playlists"); 2162702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id IN (SELECT playlist_id FROM " + 2163baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen "audio_playlists_map WHERE audio_id=?)"); 2164baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(3)); 2165702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2166702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2167702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS_ID: 2168702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_playlists"); 2169baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen qb.appendWhere("_id=?"); 2170baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(5)); 2171702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2172702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2173702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES: 2174702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_genres"); 2175702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2176702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2177702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID: 2178702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_genres"); 2179baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen qb.appendWhere("_id=?"); 2180baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(3)); 2181702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2182702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2183bfbc30ff3b9e3a96b08c525d0971d8d8543ab000Marco Nelissen case AUDIO_GENRES_ALL_MEMBERS: 2184702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID_MEMBERS: 218578b2885edc406273d688536b0eadfea006b20662Marco Nelissen { 218678b2885edc406273d688536b0eadfea006b20662Marco Nelissen // if simpleQuery is true, we can do a simpler query on just audio_genres_map 218778b2885edc406273d688536b0eadfea006b20662Marco Nelissen // we can do this if we have no keywords and our projection includes just columns 218878b2885edc406273d688536b0eadfea006b20662Marco Nelissen // from audio_genres_map 218978b2885edc406273d688536b0eadfea006b20662Marco Nelissen boolean simpleQuery = (keywords == null && projectionIn != null 219078b2885edc406273d688536b0eadfea006b20662Marco Nelissen && (selection == null || selection.equalsIgnoreCase("genre_id=?"))); 219178b2885edc406273d688536b0eadfea006b20662Marco Nelissen if (projectionIn != null) { 219278b2885edc406273d688536b0eadfea006b20662Marco Nelissen for (int i = 0; i < projectionIn.length; i++) { 219378b2885edc406273d688536b0eadfea006b20662Marco Nelissen String p = projectionIn[i]; 219478b2885edc406273d688536b0eadfea006b20662Marco Nelissen if (p.equals("_id")) { 219578b2885edc406273d688536b0eadfea006b20662Marco Nelissen // note, this is different from playlist below, because 219678b2885edc406273d688536b0eadfea006b20662Marco Nelissen // "_id" used to (wrongly) be the audio id in this query, not 219778b2885edc406273d688536b0eadfea006b20662Marco Nelissen // the row id of the entry in the map, and we preserve this 219878b2885edc406273d688536b0eadfea006b20662Marco Nelissen // behavior for backwards compatibility 219978b2885edc406273d688536b0eadfea006b20662Marco Nelissen simpleQuery = false; 220078b2885edc406273d688536b0eadfea006b20662Marco Nelissen } 220178b2885edc406273d688536b0eadfea006b20662Marco Nelissen if (simpleQuery && !(p.equals("audio_id") || 220278b2885edc406273d688536b0eadfea006b20662Marco Nelissen p.equals("genre_id"))) { 220378b2885edc406273d688536b0eadfea006b20662Marco Nelissen simpleQuery = false; 220478b2885edc406273d688536b0eadfea006b20662Marco Nelissen } 220578b2885edc406273d688536b0eadfea006b20662Marco Nelissen } 220678b2885edc406273d688536b0eadfea006b20662Marco Nelissen } 220778b2885edc406273d688536b0eadfea006b20662Marco Nelissen if (simpleQuery) { 220878b2885edc406273d688536b0eadfea006b20662Marco Nelissen qb.setTables("audio_genres_map_noid"); 2209bfbc30ff3b9e3a96b08c525d0971d8d8543ab000Marco Nelissen if (table == AUDIO_GENRES_ID_MEMBERS) { 2210baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen qb.appendWhere("genre_id=?"); 2211baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(3)); 2212bfbc30ff3b9e3a96b08c525d0971d8d8543ab000Marco Nelissen } 221378b2885edc406273d688536b0eadfea006b20662Marco Nelissen } else { 221478b2885edc406273d688536b0eadfea006b20662Marco Nelissen qb.setTables("audio_genres_map_noid, audio"); 2215bfbc30ff3b9e3a96b08c525d0971d8d8543ab000Marco Nelissen qb.appendWhere("audio._id = audio_id"); 2216bfbc30ff3b9e3a96b08c525d0971d8d8543ab000Marco Nelissen if (table == AUDIO_GENRES_ID_MEMBERS) { 2217baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen qb.appendWhere(" AND genre_id=?"); 2218baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(3)); 2219bfbc30ff3b9e3a96b08c525d0971d8d8543ab000Marco Nelissen } 222078b2885edc406273d688536b0eadfea006b20662Marco Nelissen for (int i = 0; keywords != null && i < keywords.length; i++) { 222178b2885edc406273d688536b0eadfea006b20662Marco Nelissen qb.appendWhere(" AND "); 222278b2885edc406273d688536b0eadfea006b20662Marco Nelissen qb.appendWhere(MediaStore.Audio.Media.ARTIST_KEY + 222378b2885edc406273d688536b0eadfea006b20662Marco Nelissen "||" + MediaStore.Audio.Media.ALBUM_KEY + 222478b2885edc406273d688536b0eadfea006b20662Marco Nelissen "||" + MediaStore.Audio.Media.TITLE_KEY + 2225baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen " LIKE ? ESCAPE '\\'"); 2226baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add("%" + keywords[i] + "%"); 222778b2885edc406273d688536b0eadfea006b20662Marco Nelissen } 222878b2885edc406273d688536b0eadfea006b20662Marco Nelissen } 222978b2885edc406273d688536b0eadfea006b20662Marco Nelissen } 2230702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2231702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2232702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS: 2233702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_playlists"); 2234702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2235702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2236702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID: 2237702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_playlists"); 2238baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen qb.appendWhere("_id=?"); 2239baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(3)); 2240702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2241702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2242b5f293f3888b304e0b78c0039d7326c20e778b9fMarco Nelissen case AUDIO_PLAYLISTS_ID_MEMBERS_ID: 2243702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS: 2244e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood // if simpleQuery is true, we can do a simpler query on just audio_playlists_map 2245e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood // we can do this if we have no keywords and our projection includes just columns 2246e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood // from audio_playlists_map 22474382d5ecf11d3c70eed9ba7b09970ef254774b6dMike Lockwood boolean simpleQuery = (keywords == null && projectionIn != null 22484382d5ecf11d3c70eed9ba7b09970ef254774b6dMike Lockwood && (selection == null || selection.equalsIgnoreCase("playlist_id=?"))); 224997e61d89d90a1bd6989a254660aa80553662e002Marco Nelissen if (projectionIn != null) { 225097e61d89d90a1bd6989a254660aa80553662e002Marco Nelissen for (int i = 0; i < projectionIn.length; i++) { 2251e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood String p = projectionIn[i]; 2252e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood if (simpleQuery && !(p.equals("audio_id") || 2253e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood p.equals("playlist_id") || p.equals("play_order"))) { 2254e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood simpleQuery = false; 2255e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood } 2256e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood if (p.equals("_id")) { 225797e61d89d90a1bd6989a254660aa80553662e002Marco Nelissen projectionIn[i] = "audio_playlists_map._id AS _id"; 225897e61d89d90a1bd6989a254660aa80553662e002Marco Nelissen } 2259702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2260702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2261e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood if (simpleQuery) { 2262e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood qb.setTables("audio_playlists_map"); 2263baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen qb.appendWhere("playlist_id=?"); 2264baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(3)); 2265e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood } else { 2266e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood qb.setTables("audio_playlists_map, audio"); 2267baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen qb.appendWhere("audio._id = audio_id AND playlist_id=?"); 2268baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(3)); 2269e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood for (int i = 0; keywords != null && i < keywords.length; i++) { 2270e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood qb.appendWhere(" AND "); 2271e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood qb.appendWhere(MediaStore.Audio.Media.ARTIST_KEY + 2272e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood "||" + MediaStore.Audio.Media.ALBUM_KEY + 2273e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood "||" + MediaStore.Audio.Media.TITLE_KEY + 2274baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen " LIKE ? ESCAPE '\\'"); 2275baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add("%" + keywords[i] + "%"); 2276e6300fefefc68417851efcc455cc01a4aaa60678Mike Lockwood } 2277c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen } 2278b5f293f3888b304e0b78c0039d7326c20e778b9fMarco Nelissen if (table == AUDIO_PLAYLISTS_ID_MEMBERS_ID) { 2279baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen qb.appendWhere(" AND audio_playlists_map._id=?"); 2280baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(5)); 2281b5f293f3888b304e0b78c0039d7326c20e778b9fMarco Nelissen } 2282702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2283702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2284702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA: 2285702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("video"); 2286702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2287702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA_ID: 2288702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("video"); 2289baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen qb.appendWhere("_id=?"); 2290baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(3)); 2291702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2292702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2293b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case VIDEO_THUMBNAILS_ID: 2294b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen hasThumbnailId = true; 2295b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case VIDEO_THUMBNAILS: 2296b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (!queryThumbnail(qb, uri, "videothumbnails", "video_id", hasThumbnailId)) { 2297b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return null; 2298b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 2299b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen break; 2300b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 2301702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ARTISTS: 2302d9672f4d28ab9038333a0037fe30e386ac0ce610Marco Nelissen if (projectionIn != null && projectionIn.length == 1 && selectionArgs == null 2303ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen && (selection == null || selection.length() == 0) 2304c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen && projectionIn[0].equalsIgnoreCase("count(*)") 2305c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen && keywords != null) { 2306ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen //Log.i("@@@@", "taking fast path for counting artists"); 2307ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.setTables("audio_meta"); 2308ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen projectionIn[0] = "count(distinct artist_id)"; 2309ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.appendWhere("is_music=1"); 2310ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen } else { 2311ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.setTables("artist_info"); 2312c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen for (int i = 0; keywords != null && i < keywords.length; i++) { 2313c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen if (i > 0) { 2314c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen qb.appendWhere(" AND "); 2315c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen } 2316c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen qb.appendWhere(MediaStore.Audio.Media.ARTIST_KEY + 2317baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen " LIKE ? ESCAPE '\\'"); 2318baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add("%" + keywords[i] + "%"); 2319c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen } 2320ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen } 2321702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2322702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2323702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ARTISTS_ID: 2324702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("artist_info"); 2325baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen qb.appendWhere("_id=?"); 2326baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(3)); 2327702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2328702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2329702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ARTISTS_ID_ALBUMS: 2330702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String aid = uri.getPathSegments().get(3); 2331acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen qb.setTables("audio LEFT OUTER JOIN album_art ON" + 2332acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen " audio.album_id=album_art.album_id"); 2333acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen qb.appendWhere("is_music=1 AND audio.album_id IN (SELECT album_id FROM " + 2334baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen "artists_albums_map WHERE artist_id=?)"); 2335baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(aid); 2336c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen for (int i = 0; keywords != null && i < keywords.length; i++) { 2337c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen qb.appendWhere(" AND "); 2338c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen qb.appendWhere(MediaStore.Audio.Media.ARTIST_KEY + 2339c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen "||" + MediaStore.Audio.Media.ALBUM_KEY + 2340baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen " LIKE ? ESCAPE '\\'"); 2341baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add("%" + keywords[i] + "%"); 2342c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen } 2343acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen groupBy = "audio.album_id"; 2344702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Albums.NUMBER_OF_SONGS_FOR_ARTIST, 2345acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen "count(CASE WHEN artist_id==" + aid + " THEN 'foo' ELSE NULL END) AS " + 2346702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.Audio.Albums.NUMBER_OF_SONGS_FOR_ARTIST); 2347702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setProjectionMap(sArtistAlbumsMap); 2348702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2349702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2350702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ALBUMS: 2351d9672f4d28ab9038333a0037fe30e386ac0ce610Marco Nelissen if (projectionIn != null && projectionIn.length == 1 && selectionArgs == null 2352ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen && (selection == null || selection.length() == 0) 2353c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen && projectionIn[0].equalsIgnoreCase("count(*)") 2354c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen && keywords != null) { 2355ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen //Log.i("@@@@", "taking fast path for counting albums"); 2356ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.setTables("audio_meta"); 2357ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen projectionIn[0] = "count(distinct album_id)"; 2358ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.appendWhere("is_music=1"); 2359ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen } else { 2360ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.setTables("album_info"); 2361c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen for (int i = 0; keywords != null && i < keywords.length; i++) { 2362c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen if (i > 0) { 2363c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen qb.appendWhere(" AND "); 2364c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen } 2365c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen qb.appendWhere(MediaStore.Audio.Media.ARTIST_KEY + 2366c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen "||" + MediaStore.Audio.Media.ALBUM_KEY + 2367baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen " LIKE ? ESCAPE '\\'"); 2368baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add("%" + keywords[i] + "%"); 2369c38530b8c1935f629023df6e9a478c2c801bdddaMarco Nelissen } 2370ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen } 2371702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2372702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2373702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ALBUMS_ID: 2374702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("album_info"); 2375baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen qb.appendWhere("_id=?"); 2376baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(3)); 2377702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2378702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2379702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ALBUMART_ID: 2380702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("album_art"); 2381baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen qb.appendWhere("album_id=?"); 2382baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(3)); 2383702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2384702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2385a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen case AUDIO_SEARCH_LEGACY: 2386a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen Log.w(TAG, "Legacy media search Uri used. Please update your code."); 2387a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // fall through 2388a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen case AUDIO_SEARCH_FANCY: 2389a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen case AUDIO_SEARCH_BASIC: 2390baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen return doAudioSearch(db, qb, uri, projectionIn, selection, 2391baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen combine(prependArgs, selectionArgs), sort, table, limit); 2392702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 239316dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood case FILES_ID: 2394e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood case MTP_OBJECTS_ID: 2395baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen qb.appendWhere("_id=?"); 2396baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen prependArgs.add(uri.getPathSegments().get(2)); 2397b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood // fall through 239816dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood case FILES: 2399e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood case MTP_OBJECTS: 240016dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood qb.setTables("files"); 2401b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood break; 2402b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 2403e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood case MTP_OBJECT_REFERENCES: 2404e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood int handle = Integer.parseInt(uri.getPathSegments().get(2)); 240510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen return getObjectReferences(helper, db, handle); 2406e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood 2407702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project default: 2408702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalStateException("Unknown URL: " + uri.toString()); 2409702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2410702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2411baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen // Log.v(TAG, "query = "+ qb.buildQuery(projectionIn, selection, 2412baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen // combine(prependArgs, selectionArgs), groupBy, null, sort, limit)); 2413702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Cursor c = qb.query(db, projectionIn, selection, 2414baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen combine(prependArgs, selectionArgs), groupBy, null, sort, limit); 2415b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 2416702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (c != null) { 2417702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project c.setNotificationUri(getContext().getContentResolver(), uri); 2418702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2419b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 2420702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return c; 2421702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2422702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2423baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen private String[] combine(List<String> prepend, String[] userArgs) { 2424baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen int presize = prepend.size(); 2425baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen if (presize == 0) { 2426baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen return userArgs; 2427baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen } 2428baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen 2429baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen int usersize = (userArgs != null) ? userArgs.length : 0; 2430baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen String [] combined = new String[presize + usersize]; 2431baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen for (int i = 0; i < presize; i++) { 2432baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen combined[i] = prepend.get(i); 2433baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen } 2434baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen for (int i = 0; i < usersize; i++) { 2435baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen combined[presize + i] = userArgs[i]; 2436baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen } 2437baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen return combined; 2438baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen } 2439baffe34089b74c09d549c963da24ffb80f6682f4Marco Nelissen 2440702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private Cursor doAudioSearch(SQLiteDatabase db, SQLiteQueryBuilder qb, 2441702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Uri uri, String[] projectionIn, String selection, 24424574e03055af60fada50481f2b34e19a687d5866Marco Nelissen String[] selectionArgs, String sort, int mode, 24434574e03055af60fada50481f2b34e19a687d5866Marco Nelissen String limit) { 2444702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 244518c787fb045725bf10bf630ac0917a48def9ace5Marco Nelissen String mSearchString = uri.getPath().endsWith("/") ? "" : uri.getLastPathSegment(); 2446702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mSearchString = mSearchString.replaceAll(" ", " ").trim().toLowerCase(); 2447702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2448702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String [] searchWords = mSearchString.length() > 0 ? 2449702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mSearchString.split(" ") : new String[0]; 2450a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen String [] wildcardWords = new String[searchWords.length]; 2451702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Collator col = Collator.getInstance(); 2452702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project col.setStrength(Collator.PRIMARY); 2453702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int len = searchWords.length; 2454702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project for (int i = 0; i < len; i++) { 2455702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Because we match on individual words here, we need to remove words 2456702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // like 'a' and 'the' that aren't part of the keys. 24573001ef332046c69cbb70289be29442fcc0ad5f6fMarco Nelissen String key = MediaStore.Audio.keyFor(searchWords[i]); 24583001ef332046c69cbb70289be29442fcc0ad5f6fMarco Nelissen key = key.replace("\\", "\\\\"); 24593001ef332046c69cbb70289be29442fcc0ad5f6fMarco Nelissen key = key.replace("%", "\\%"); 24603001ef332046c69cbb70289be29442fcc0ad5f6fMarco Nelissen key = key.replace("_", "\\_"); 2461a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen wildcardWords[i] = 2462702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project (searchWords[i].equals("a") || searchWords[i].equals("an") || 24633001ef332046c69cbb70289be29442fcc0ad5f6fMarco Nelissen searchWords[i].equals("the")) ? "%" : "%" + key + "%"; 2464702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2465702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2466a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen String where = ""; 2467a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen for (int i = 0; i < searchWords.length; i++) { 2468a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen if (i == 0) { 24693001ef332046c69cbb70289be29442fcc0ad5f6fMarco Nelissen where = "match LIKE ? ESCAPE '\\'"; 2470a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen } else { 24713001ef332046c69cbb70289be29442fcc0ad5f6fMarco Nelissen where += " AND match LIKE ? ESCAPE '\\'"; 2472702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2473702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2474702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2475a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen qb.setTables("search"); 2476a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen String [] cols; 2477a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen if (mode == AUDIO_SEARCH_FANCY) { 2478a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen cols = mSearchColsFancy; 2479a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen } else if (mode == AUDIO_SEARCH_BASIC) { 2480a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen cols = mSearchColsBasic; 2481a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen } else { 2482a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen cols = mSearchColsLegacy; 2483702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 24844574e03055af60fada50481f2b34e19a687d5866Marco Nelissen return qb.query(db, cols, where, wildcardWords, null, null, null, limit); 2485702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2486702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2487702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 2488702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public String getType(Uri url) 2489702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project { 2490702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (URI_MATCHER.match(url)) { 2491702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA_ID: 2492702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID: 2493702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS_ID: 2494702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA_ID: 2495c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood case FILES_ID: 249626f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen Cursor c = null; 249726f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen try { 249826f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen c = query(url, MIME_TYPE_PROJECTION, null, null, null); 249926f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen if (c != null && c.getCount() == 1) { 250026f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen c.moveToFirst(); 250126f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen String mimeType = c.getString(1); 250226f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen c.deactivate(); 250326f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen return mimeType; 250426f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen } 250526f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen } finally { 250626f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen if (c != null) { 250726f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen c.close(); 250826f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen } 2509702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2510702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2511702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2512702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA: 2513702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_THUMBNAILS: 2514702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Images.Media.CONTENT_TYPE; 2515804f5fe841d4a96f9335ea60d60853352f726227Marco Nelissen case AUDIO_ALBUMART_ID: 2516702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_THUMBNAILS_ID: 2517702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return "image/jpeg"; 2518702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2519702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA: 2520702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID_MEMBERS: 2521702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS: 2522702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Audio.Media.CONTENT_TYPE; 2523702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2524702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES: 2525702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES: 2526702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Audio.Genres.CONTENT_TYPE; 2527702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID: 2528702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES_ID: 2529702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Audio.Genres.ENTRY_CONTENT_TYPE; 2530702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS: 2531702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS: 2532702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Audio.Playlists.CONTENT_TYPE; 2533702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID: 2534702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS_ID: 2535702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Audio.Playlists.ENTRY_CONTENT_TYPE; 2536702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2537702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA: 2538702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Video.Media.CONTENT_TYPE; 2539702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2540804f5fe841d4a96f9335ea60d60853352f726227Marco Nelissen throw new IllegalStateException("Unknown URL : " + url); 2541702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2542702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2543702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 2544702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Ensures there is a file in the _data column of values, if one isn't 2545702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * present a new file is created. 2546702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 2547702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param initialValues the values passed to insert by the caller 2548702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @return the new values 2549702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 2550702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private ContentValues ensureFile(boolean internal, ContentValues initialValues, 2551702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String preferredExtension, String directoryName) { 2552702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values; 2553801ba04ac37ee06dccb8bf4081b29a162795e3a6Mike Lockwood String file = initialValues.getAsString(MediaStore.MediaColumns.DATA); 2554702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (TextUtils.isEmpty(file)) { 2555702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project file = generateFileName(internal, preferredExtension, directoryName); 2556702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values = new ContentValues(initialValues); 2557801ba04ac37ee06dccb8bf4081b29a162795e3a6Mike Lockwood values.put(MediaStore.MediaColumns.DATA, file); 2558702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 2559702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values = initialValues; 2560702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2561702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2562702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!ensureFileExists(file)) { 2563702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalStateException("Unable to create new file: " + file); 2564702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2565702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return values; 2566702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2567702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2568d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood private void sendObjectAdded(long objectHandle) { 256934be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood synchronized (mMtpServiceConnection) { 257034be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood if (mMtpService != null) { 257134be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood try { 257234be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood mMtpService.sendObjectAdded((int)objectHandle); 257334be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood } catch (RemoteException e) { 257434be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood Log.e(TAG, "RemoteException in sendObjectAdded", e); 257534be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood mMtpService = null; 257634be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood } 2577d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 2578d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 2579d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 2580d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 2581d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood private void sendObjectRemoved(long objectHandle) { 258234be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood synchronized (mMtpServiceConnection) { 258334be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood if (mMtpService != null) { 258434be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood try { 258534be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood mMtpService.sendObjectRemoved((int)objectHandle); 258634be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood } catch (RemoteException e) { 258734be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood Log.e(TAG, "RemoteException in sendObjectRemoved", e); 258834be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood mMtpService = null; 258934be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood } 2590d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 2591d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 2592d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 2593d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood 2594702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 2595702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public int bulkInsert(Uri uri, ContentValues values[]) { 2596702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int match = URI_MATCHER.match(uri); 2597702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (match == VOLUMES) { 2598702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return super.bulkInsert(uri, values); 2599702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 260010af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen DatabaseHelper helper = getDatabaseForUri(uri); 260110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen if (helper == null) { 2602702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException( 2603702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Unknown URI: " + uri); 2604702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 260510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen SQLiteDatabase db = helper.getWritableDatabase(); 26065fde670987a55d69442566dcbdb7830d5f1587c6Chih-Chung Chang if (db == null) { 26075fde670987a55d69442566dcbdb7830d5f1587c6Chih-Chung Chang throw new IllegalStateException("Couldn't open database for " + uri); 26085fde670987a55d69442566dcbdb7830d5f1587c6Chih-Chung Chang } 2609ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen 2610ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen if (match == AUDIO_PLAYLISTS_ID || match == AUDIO_PLAYLISTS_ID_MEMBERS) { 2611ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen return playlistBulkInsert(db, uri, values); 2612e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } else if (match == MTP_OBJECT_REFERENCES) { 2613e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood int handle = Integer.parseInt(uri.getPathSegments().get(2)); 261410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen return setObjectReferences(helper, db, handle, values); 2615ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen } 2616ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen 2617702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.beginTransaction(); 2618702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int numInserted = 0; 2619702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 2620702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int len = values.length; 2621702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project for (int i = 0; i < len; i++) { 2622801ba04ac37ee06dccb8bf4081b29a162795e3a6Mike Lockwood if (values[i] != null) { 2623801ba04ac37ee06dccb8bf4081b29a162795e3a6Mike Lockwood insertInternal(uri, match, values[i]); 2624801ba04ac37ee06dccb8bf4081b29a162795e3a6Mike Lockwood } 2625702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2626702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project numInserted = len; 2627702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.setTransactionSuccessful(); 2628702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 2629702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.endTransaction(); 2630702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2631702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 2632702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return numInserted; 2633702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2634702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2635702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 2636801ba04ac37ee06dccb8bf4081b29a162795e3a6Mike Lockwood public Uri insert(Uri uri, ContentValues initialValues) { 26375d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood int match = URI_MATCHER.match(uri); 26385d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood Uri newUri = insertInternal(uri, match, initialValues); 26395d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood // do not signal notification for MTP objects. 26405d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood // we will signal instead after file transfer is successful. 2641e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood if (newUri != null && match != MTP_OBJECTS) { 2642702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 2643702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2644702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return newUri; 2645702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2646702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2647ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen private int playlistBulkInsert(SQLiteDatabase db, Uri uri, ContentValues values[]) { 2648ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen DatabaseUtils.InsertHelper helper = 2649ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen new DatabaseUtils.InsertHelper(db, "audio_playlists_map"); 26508b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen int audioidcolidx = helper.getColumnIndex(MediaStore.Audio.Playlists.Members.AUDIO_ID); 26518b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen int playlistididx = helper.getColumnIndex(Audio.Playlists.Members.PLAYLIST_ID); 26528b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen int playorderidx = helper.getColumnIndex(MediaStore.Audio.Playlists.Members.PLAY_ORDER); 26538b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen long playlistId = Long.parseLong(uri.getPathSegments().get(3)); 2654ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen 2655ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen db.beginTransaction(); 2656ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen int numInserted = 0; 2657ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen try { 2658ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen int len = values.length; 2659ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen for (int i = 0; i < len; i++) { 26608b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen helper.prepareForInsert(); 26618b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen // getting the raw Object and converting it long ourselves saves 26628b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen // an allocation (the alternative is ContentValues.getAsLong, which 26638b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen // returns a Long object) 26648b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen long audioid = ((Number) values[i].get( 26658b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen MediaStore.Audio.Playlists.Members.AUDIO_ID)).longValue(); 26668b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen helper.bind(audioidcolidx, audioid); 26678b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen helper.bind(playlistididx, playlistId); 26688b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen // convert to int ourselves to save an allocation. 26698b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen int playorder = ((Number) values[i].get( 26708b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen MediaStore.Audio.Playlists.Members.PLAY_ORDER)).intValue(); 26718b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen helper.bind(playorderidx, playorder); 26728b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen helper.execute(); 2673ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen } 2674ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen numInserted = len; 2675ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen db.setTransactionSuccessful(); 2676ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen } finally { 2677ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen db.endTransaction(); 2678ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen helper.close(); 2679ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen } 2680ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen getContext().getContentResolver().notifyChange(uri, null); 2681ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen return numInserted; 2682ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen } 2683ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen 268410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen private long insertDirectory(DatabaseHelper helper, SQLiteDatabase db, String path) { 268510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen if (LOCAL_LOGV) Log.v(TAG, "inserting directory " + path); 2686ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood ContentValues values = new ContentValues(); 2687ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood values.put(FileColumns.FORMAT, MtpConstants.FORMAT_ASSOCIATION); 2688ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood values.put(FileColumns.DATA, path); 268910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen values.put(FileColumns.PARENT, getParent(helper, db, path)); 26909be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood values.put(FileColumns.STORAGE_ID, getStorageId(path)); 2691f2921d9af0a43c4be56a88990b55efe86fc7bb29Mike Lockwood File file = new File(path); 2692f2921d9af0a43c4be56a88990b55efe86fc7bb29Mike Lockwood if (file.exists()) { 2693f2921d9af0a43c4be56a88990b55efe86fc7bb29Mike Lockwood values.put(FileColumns.DATE_MODIFIED, file.lastModified() / 1000); 2694f2921d9af0a43c4be56a88990b55efe86fc7bb29Mike Lockwood } 269510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumInserts++; 2696ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood long rowId = db.insert("files", FileColumns.DATE_MODIFIED, values); 2697ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood sendObjectAdded(rowId); 2698ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood return rowId; 2699ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood } 2700ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood 270110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen private long getParent(DatabaseHelper helper, SQLiteDatabase db, String path) { 2702b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood int lastSlash = path.lastIndexOf('/'); 2703b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood if (lastSlash > 0) { 2704b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood String parentPath = path.substring(0, lastSlash); 27059be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood for (int i = 0; i < mExternalStoragePaths.length; i++) { 27069be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood if (parentPath.equals(mExternalStoragePaths[i])) { 27079be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood return 0; 27089be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood } 2709b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } 27107f36494e085c26c69cd5925e54028822025eff29Marco Nelissen Long cid = mDirectoryCache.get(parentPath); 27117f36494e085c26c69cd5925e54028822025eff29Marco Nelissen if (cid != null) { 27127f36494e085c26c69cd5925e54028822025eff29Marco Nelissen if (LOCAL_LOGV) Log.v(TAG, "Returning cached entry for " + parentPath); 27137f36494e085c26c69cd5925e54028822025eff29Marco Nelissen return cid; 27147f36494e085c26c69cd5925e54028822025eff29Marco Nelissen } 27157f36494e085c26c69cd5925e54028822025eff29Marco Nelissen 2716f7cc647081f0421c0247de275fa0754b29938c07Mike Lockwood // Use "LIKE" instead of "=" on case insensitive file systems so we do a 2717f7cc647081f0421c0247de275fa0754b29938c07Mike Lockwood // case insensitive match when looking for parent directory. 27187f36494e085c26c69cd5925e54028822025eff29Marco Nelissen // TODO: investigate whether a "nocase" constraint on the column and 27197f36494e085c26c69cd5925e54028822025eff29Marco Nelissen // using "=" would give the same result faster. 2720f7cc647081f0421c0247de275fa0754b29938c07Mike Lockwood String selection = (mCaseInsensitivePaths ? MediaStore.MediaColumns.DATA + " LIKE ?" 2721a9bb89771934314157dd26253195dc16bddc2cfaDongwon Kang // search only directories. 272210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen + " AND format=" + MtpConstants.FORMAT_ASSOCIATION 2723f7cc647081f0421c0247de275fa0754b29938c07Mike Lockwood : MediaStore.MediaColumns.DATA + "=?"); 2724b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood String [] selargs = { parentPath }; 272510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumQueries++; 27267f36494e085c26c69cd5925e54028822025eff29Marco Nelissen Cursor c = db.query("files", sIdOnlyColumn, selection, selargs, null, null, null); 2727b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood try { 27287f36494e085c26c69cd5925e54028822025eff29Marco Nelissen long id; 2729b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood if (c == null || c.getCount() == 0) { 2730b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood // parent isn't in the database - so add it 273110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen id = insertDirectory(helper, db, parentPath); 27327f36494e085c26c69cd5925e54028822025eff29Marco Nelissen if (LOCAL_LOGV) Log.v(TAG, "Inserted " + parentPath); 2733b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } else { 2734b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood c.moveToFirst(); 27357f36494e085c26c69cd5925e54028822025eff29Marco Nelissen id = c.getLong(0); 27367f36494e085c26c69cd5925e54028822025eff29Marco Nelissen if (LOCAL_LOGV) Log.v(TAG, "Queried " + parentPath); 2737b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } 27387f36494e085c26c69cd5925e54028822025eff29Marco Nelissen mDirectoryCache.put(parentPath, id); 27397f36494e085c26c69cd5925e54028822025eff29Marco Nelissen return id; 2740b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } finally { 2741b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood if (c != null) c.close(); 2742b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } 2743b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } else { 2744b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood return 0; 2745b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } 2746b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } 2747b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 27489be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood private int getStorageId(String path) { 27499be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood for (int i = 0; i < mExternalStoragePaths.length; i++) { 27509be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood String test = mExternalStoragePaths[i]; 27519be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood if (path.startsWith(test)) { 27529be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood int length = test.length(); 27539be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood if (path.length() == length || path.charAt(length) == '/') { 27549be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood return MtpStorage.getStorageId(i); 27559be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood } 27569be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood } 27579be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood } 27589be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood // default to primary storage 27599be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood return MtpStorage.getStorageId(0); 27609be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood } 27619be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood 276210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen private long insertFile(DatabaseHelper helper, Uri uri, ContentValues initialValues, int mediaType, 2763afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood boolean notify) { 276410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen SQLiteDatabase db = helper.getWritableDatabase(); 2765afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood ContentValues values = null; 2766afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 2767afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood switch (mediaType) { 2768afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood case FileColumns.MEDIA_TYPE_IMAGE: { 276910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen values = ensureFile(helper.mInternal, initialValues, ".jpg", "DCIM/Camera"); 2770afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 2771afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values.put(MediaStore.MediaColumns.DATE_ADDED, System.currentTimeMillis() / 1000); 2772afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood String data = values.getAsString(MediaColumns.DATA); 2773afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (! values.containsKey(MediaColumns.DISPLAY_NAME)) { 2774afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood computeDisplayName(data, values); 2775afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2776afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood computeTakenTime(values); 2777afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood break; 2778afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2779afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 2780afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood case FileColumns.MEDIA_TYPE_AUDIO: { 2781afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // SQLite Views are read-only, so we need to deconstruct this 2782afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // insert and do inserts into the underlying tables. 2783afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // If doing this here turns out to be a performance bottleneck, 2784afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // consider moving this to native code and using triggers on 2785afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // the view. 2786afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values = new ContentValues(initialValues); 2787afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 27882658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen String albumartist = values.getAsString(MediaStore.Audio.Media.ALBUM_ARTIST); 27892658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen String compilation = values.getAsString(MediaStore.Audio.Media.COMPILATION); 27902658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen values.remove(MediaStore.Audio.Media.COMPILATION); 27912658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen 2792afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // Insert the artist into the artist table and remove it from 2793afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // the input values 2794afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood Object so = values.get("artist"); 2795afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood String s = (so == null ? "" : so.toString()); 2796afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values.remove("artist"); 2797afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood long artistRowId; 279810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen HashMap<String, Long> artistCache = helper.mArtistCache; 2799801ba04ac37ee06dccb8bf4081b29a162795e3a6Mike Lockwood String path = values.getAsString(MediaStore.MediaColumns.DATA); 2800afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood synchronized(artistCache) { 2801afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood Long temp = artistCache.get(s); 2802afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (temp == null) { 280310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen artistRowId = getKeyIdForName(helper, db, 280410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen "artists", "artist_key", "artist", 2805afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood s, s, path, 0, null, artistCache, uri); 2806afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } else { 2807afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood artistRowId = temp.longValue(); 2808afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2809afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2810afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood String artist = s; 2811afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 2812afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // Do the same for the album field 2813afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood so = values.get("album"); 2814afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood s = (so == null ? "" : so.toString()); 2815afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values.remove("album"); 2816afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood long albumRowId; 281710af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen HashMap<String, Long> albumCache = helper.mAlbumCache; 2818afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood synchronized(albumCache) { 28192658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen int albumhash = 0; 28202658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen if (albumartist != null) { 28212658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen albumhash = albumartist.hashCode(); 28222658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen } else if (compilation != null && compilation.equals("1")) { 28232658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen // nothing to do, hash already set 28242658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen } else { 28252658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen albumhash = path.substring(0, path.lastIndexOf('/')).hashCode(); 28262658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen } 2827afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood String cacheName = s + albumhash; 2828afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood Long temp = albumCache.get(cacheName); 2829afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (temp == null) { 283010af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen albumRowId = getKeyIdForName(helper, db, 283110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen "albums", "album_key", "album", 2832afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood s, cacheName, path, albumhash, artist, albumCache, uri); 2833afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } else { 2834afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood albumRowId = temp; 2835afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2836afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 28375d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood 2838afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values.put("artist_id", Integer.toString((int)artistRowId)); 2839afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values.put("album_id", Integer.toString((int)albumRowId)); 2840afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood so = values.getAsString("title"); 2841afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood s = (so == null ? "" : so.toString()); 2842afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values.put("title_key", MediaStore.Audio.keyFor(s)); 2843afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // do a final trim of the title, in case it started with the special 2844afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // "sort first" character (ascii \001) 2845afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values.remove("title"); 2846afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values.put("title", s.trim()); 2847b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 2848801ba04ac37ee06dccb8bf4081b29a162795e3a6Mike Lockwood computeDisplayName(values.getAsString(MediaStore.MediaColumns.DATA), values); 2849afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood break; 2850afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2851afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 2852afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood case FileColumns.MEDIA_TYPE_VIDEO: { 285310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen values = ensureFile(helper.mInternal, initialValues, ".3gp", "video"); 2854801ba04ac37ee06dccb8bf4081b29a162795e3a6Mike Lockwood String data = values.getAsString(MediaStore.MediaColumns.DATA); 2855afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood computeDisplayName(data, values); 2856afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood computeTakenTime(values); 2857afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood break; 2858afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2859afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2860afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 2861afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (values == null) { 2862afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values = new ContentValues(initialValues); 2863afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2864fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood // compute bucket_id and bucket_display_name for all files 2865afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood String path = values.getAsString(MediaStore.MediaColumns.DATA); 2866fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood if (path != null) { 2867fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood computeBucketValues(path, values); 2868fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood } 2869fb598dd5ac235f6282aac23b7b9c214f2fd62a7aMike Lockwood values.put(MediaStore.MediaColumns.DATE_ADDED, System.currentTimeMillis() / 1000); 2870afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 2871afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood long rowId = 0; 2872afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood Integer i = values.getAsInteger( 2873afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood MediaStore.MediaColumns.MEDIA_SCANNER_NEW_OBJECT_ID); 2874afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (i != null) { 2875afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood rowId = i.intValue(); 2876afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values = new ContentValues(values); 2877afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values.remove(MediaStore.MediaColumns.MEDIA_SCANNER_NEW_OBJECT_ID); 2878afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2879afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 2880afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood String title = values.getAsString(MediaStore.MediaColumns.TITLE); 28813572ac7fc911cda5e4ac60af9455820a7ddf6593Marco Nelissen if (title == null && path != null) { 2882c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood title = MediaFile.getFileTitle(path); 2883c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood } 2884c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood values.put(FileColumns.TITLE, title); 2885c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood 2886afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood String mimeType = values.getAsString(MediaStore.MediaColumns.MIME_TYPE); 2887afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood Integer formatObject = values.getAsInteger(FileColumns.FORMAT); 2888c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood int format = (formatObject == null ? 0 : formatObject.intValue()); 2889c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood if (format == 0) { 289063b4ed85f500e23297ad5eb530318e06b9ab2289Dongwon Kang if (TextUtils.isEmpty(path)) { 2891c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood // special case device created playlists 2892afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (mediaType == FileColumns.MEDIA_TYPE_PLAYLIST) { 2893c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood values.put(FileColumns.FORMAT, MtpConstants.FORMAT_ABSTRACT_AV_PLAYLIST); 2894c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood // create a file path for the benefit of MTP 28959be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood path = mExternalStoragePaths[0] 2896afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + "/Playlists/" + values.getAsString(Audio.Playlists.NAME); 2897c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood values.put(MediaStore.MediaColumns.DATA, path); 289810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen values.put(FileColumns.PARENT, getParent(helper, db, path)); 2899c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood } else { 290063b4ed85f500e23297ad5eb530318e06b9ab2289Dongwon Kang Log.e(TAG, "path is empty in insertFile()"); 2901c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood } 2902c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood } else { 2903c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood format = MediaFile.getFormatCode(path, mimeType); 2904c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood } 2905c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood } 2906c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood if (format != 0) { 2907c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood values.put(FileColumns.FORMAT, format); 2908c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood if (mimeType == null) { 2909c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood mimeType = MediaFile.getMimeTypeForFormatCode(format); 2910c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood } 2911c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood } 2912c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood 2913801ba04ac37ee06dccb8bf4081b29a162795e3a6Mike Lockwood if (mimeType == null && path != null) { 2914c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood mimeType = MediaFile.getMimeTypeForFile(path); 2915c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood } 2916c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood if (mimeType != null) { 2917c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood values.put(FileColumns.MIME_TYPE, mimeType); 2918afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 2919f1f6a9e343033de33fc748f659b9221f8d5b06e1Mike Lockwood if (mediaType == FileColumns.MEDIA_TYPE_NONE && !MediaScanner.isNoMediaPath(path)) { 2920afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood int fileType = MediaFile.getFileTypeForMimeType(mimeType); 2921afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (MediaFile.isAudioFileType(fileType)) { 2922afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood mediaType = FileColumns.MEDIA_TYPE_AUDIO; 2923afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } else if (MediaFile.isVideoFileType(fileType)) { 2924afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood mediaType = FileColumns.MEDIA_TYPE_VIDEO; 2925afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } else if (MediaFile.isImageFileType(fileType)) { 2926afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood mediaType = FileColumns.MEDIA_TYPE_IMAGE; 2927afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } else if (MediaFile.isPlayListFileType(fileType)) { 2928afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood mediaType = FileColumns.MEDIA_TYPE_PLAYLIST; 2929afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2930afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2931c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood } 2932afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood values.put(FileColumns.MEDIA_TYPE, mediaType); 2933c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood 2934afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (rowId == 0) { 2935afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (mediaType == FileColumns.MEDIA_TYPE_PLAYLIST) { 29363572ac7fc911cda5e4ac60af9455820a7ddf6593Marco Nelissen String name = values.getAsString(Audio.Playlists.NAME); 2937282dc90a0e201d992cdd0d0176028da6a565f9d5Mike Lockwood if (name == null && path == null) { 2938282dc90a0e201d992cdd0d0176028da6a565f9d5Mike Lockwood // MediaScanner will compute the name from the path if we have one 2939afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood throw new IllegalArgumentException( 2940282dc90a0e201d992cdd0d0176028da6a565f9d5Mike Lockwood "no name was provided when inserting abstract playlist"); 2941afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2942afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } else { 2943a36cfaef630ef5df7bef80b25f6bd493d040c7e4Brian Muramatsu if (path == null) { 2944afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // path might be null for playlists created on the device 2945afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // or transfered via MTP 2946afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood throw new IllegalArgumentException( 2947afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "no path was provided when inserting new file"); 2948afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 2949e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 2950b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 2951f2921d9af0a43c4be56a88990b55efe86fc7bb29Mike Lockwood // make sure modification date and size are set 2952f2921d9af0a43c4be56a88990b55efe86fc7bb29Mike Lockwood if (path != null) { 2953f2921d9af0a43c4be56a88990b55efe86fc7bb29Mike Lockwood File file = new File(path); 2954f2921d9af0a43c4be56a88990b55efe86fc7bb29Mike Lockwood if (file.exists()) { 2955f2921d9af0a43c4be56a88990b55efe86fc7bb29Mike Lockwood values.put(FileColumns.DATE_MODIFIED, file.lastModified() / 1000); 295616dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood values.put(FileColumns.SIZE, file.length()); 2957e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 29585d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood } 2959b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 2960afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood Long parent = values.getAsLong(FileColumns.PARENT); 29615d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood if (parent == null) { 2962e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (path != null) { 296310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen long parentId = getParent(helper, db, path); 296416dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood values.put(FileColumns.PARENT, parentId); 2965e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 29669be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood } 29679be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood Integer storage = values.getAsInteger(FileColumns.STORAGE_ID); 29689be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood if (storage == null) { 29699be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood int storageId = getStorageId(path); 29709be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood values.put(FileColumns.STORAGE_ID, storageId); 29715d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood } 2972b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 297310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumInserts++; 2974afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood rowId = db.insert("files", FileColumns.DATE_MODIFIED, values); 2975afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (LOCAL_LOGV) Log.v(TAG, "insertFile: values=" + values + " returned: " + rowId); 2976afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 297710af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen if (rowId != -1 && notify) { 2978afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood sendObjectAdded(rowId); 2979afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood } 29805d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood } else { 298110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumUpdates++; 298216dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood db.update("files", values, FileColumns._ID + "=?", 2983afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood new String[] { Long.toString(rowId) }); 29845d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood } 2985d4e1312b4927b2bdd1f47e3d989f7293635c1125Marco Nelissen if (format == MtpConstants.FORMAT_ASSOCIATION) { 2986d4e1312b4927b2bdd1f47e3d989f7293635c1125Marco Nelissen mDirectoryCache.put(path, rowId); 2987d4e1312b4927b2bdd1f47e3d989f7293635c1125Marco Nelissen } 2988afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood 2989afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood return rowId; 29901717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood } 29911717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood 299210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen private Cursor getObjectReferences(DatabaseHelper helper, SQLiteDatabase db, int handle) { 299310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumQueries++; 2994a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen Cursor c = db.query("files", sMediaTableColumns, "_id=?", 2995e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood new String[] { Integer.toString(handle) }, 2996e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood null, null, null); 2997e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood try { 2998e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (c != null && c.moveToNext()) { 2999afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood long playlistId = c.getLong(0); 3000afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood int mediaType = c.getInt(1); 3001afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (mediaType != FileColumns.MEDIA_TYPE_PLAYLIST) { 3002e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood // we only support object references for playlist objects 3003e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood return null; 3004e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 300510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumQueries++; 3006e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood return db.rawQuery(OBJECT_REFERENCES_QUERY, 3007afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood new String[] { Long.toString(playlistId) } ); 3008e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 3009e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } finally { 3010e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (c != null) { 3011e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood c.close(); 3012e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 3013e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 3014e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood return null; 3015e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 3016e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood 301710af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen private int setObjectReferences(DatabaseHelper helper, SQLiteDatabase db, 301810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen int handle, ContentValues values[]) { 3019e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood // first look up the media table and media ID for the object 3020e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood long playlistId = 0; 302110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumQueries++; 3022a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen Cursor c = db.query("files", sMediaTableColumns, "_id=?", 3023e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood new String[] { Integer.toString(handle) }, 3024e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood null, null, null); 3025e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood try { 3026e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (c != null && c.moveToNext()) { 3027afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood int mediaType = c.getInt(1); 3028afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (mediaType != FileColumns.MEDIA_TYPE_PLAYLIST) { 3029e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood // we only support object references for playlist objects 3030e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood return 0; 3031e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 3032afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood playlistId = c.getLong(0); 3033e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 3034e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } finally { 3035e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (c != null) { 3036e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood c.close(); 3037e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 3038e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 3039e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (playlistId == 0) { 3040e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood return 0; 3041e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 3042e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood 3043e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood // next delete any existing entries 304410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumDeletes++; 304510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen db.delete("audio_playlists_map", "playlist_id=?", 3046e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood new String[] { Long.toString(playlistId) }); 3047e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood 3048e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood // finally add the new entries 3049e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood int count = values.length; 3050e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood int added = 0; 3051e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood ContentValues[] valuesList = new ContentValues[count]; 3052e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood for (int i = 0; i < count; i++) { 3053e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood // convert object ID to audio ID 3054e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood long audioId = 0; 3055e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood long objectId = values[i].getAsLong(MediaStore.MediaColumns._ID); 305610af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumQueries++; 3057a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen c = db.query("files", sMediaTableColumns, "_id=?", 3058e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood new String[] { Long.toString(objectId) }, 3059e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood null, null, null); 3060e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood try { 3061e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (c != null && c.moveToNext()) { 3062afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood int mediaType = c.getInt(1); 306350d8650456d93e2107b9163e119c2eb9de73f804Mike Lockwood if (mediaType != FileColumns.MEDIA_TYPE_AUDIO) { 3064e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood // we only allow audio files in playlists, so skip 3065e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood continue; 3066e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 3067afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood audioId = c.getLong(0); 3068e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 3069e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } finally { 3070e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (c != null) { 3071e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood c.close(); 3072e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 3073e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 3074e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (audioId != 0) { 3075e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood ContentValues v = new ContentValues(); 3076e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood v.put(MediaStore.Audio.Playlists.Members.PLAYLIST_ID, playlistId); 3077e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood v.put(MediaStore.Audio.Playlists.Members.AUDIO_ID, audioId); 3078a08bc533a5f7bf9aea49b25a549b4f5b3c14f47dMike Lockwood v.put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, added); 3079a08bc533a5f7bf9aea49b25a549b4f5b3c14f47dMike Lockwood valuesList[added++] = v; 3080e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 3081e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 3082e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood if (added < count) { 3083e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood // we weren't able to find everything on the list, so lets resize the array 3084e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood // and pass what we have. 3085e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood ContentValues[] newValues = new ContentValues[added]; 3086e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood System.arraycopy(valuesList, 0, newValues, 0, added); 3087e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood valuesList = newValues; 3088e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 3089e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood return playlistBulkInsert(db, 3090e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood Audio.Playlists.Members.getContentUri(EXTERNAL_VOLUME, playlistId), 3091e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood valuesList); 3092e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood } 3093e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood 3094b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood private static final String[] GENRE_LOOKUP_PROJECTION = new String[] { 3095b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood Audio.Genres._ID, // 0 3096b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood Audio.Genres.NAME, // 1 3097b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood }; 3098b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood 3099b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood private void updateGenre(long rowId, String genre) { 3100b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood Uri uri = null; 3101b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood Cursor cursor = null; 3102b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood Uri genresUri = MediaStore.Audio.Genres.getContentUri("external"); 3103b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood try { 3104b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood // see if the genre already exists 3105b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood cursor = query(genresUri, GENRE_LOOKUP_PROJECTION, MediaStore.Audio.Genres.NAME + "=?", 3106b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood new String[] { genre }, null); 3107b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood if (cursor == null || cursor.getCount() == 0) { 3108b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood // genre does not exist, so create the genre in the genre table 3109b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood ContentValues values = new ContentValues(); 3110b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood values.put(MediaStore.Audio.Genres.NAME, genre); 3111b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood uri = insert(genresUri, values); 3112b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood } else { 3113b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood // genre already exists, so compute its Uri 3114b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood cursor.moveToNext(); 3115b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood uri = ContentUris.withAppendedId(genresUri, cursor.getLong(0)); 3116b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood } 3117b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood if (uri != null) { 3118b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood uri = Uri.withAppendedPath(uri, MediaStore.Audio.Genres.Members.CONTENT_DIRECTORY); 3119b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood } 3120b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood } finally { 3121b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood // release the cursor if it exists 3122b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood if (cursor != null) { 3123b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood cursor.close(); 3124b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood } 3125b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood } 3126b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood 3127b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood if (uri != null) { 3128b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood // add entry to audio_genre_map 3129b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood ContentValues values = new ContentValues(); 3130b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood values.put(MediaStore.Audio.Genres.Members.AUDIO_ID, Long.valueOf(rowId)); 3131b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood insert(uri, values); 3132b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood } 3133b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood } 3134b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood 31355d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood private Uri insertInternal(Uri uri, int match, ContentValues initialValues) { 3136702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long rowId; 3137702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3138d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood if (LOCAL_LOGV) Log.v(TAG, "insertInternal: "+uri+", initValues="+initialValues); 3139702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // handle MEDIA_SCANNER before calling getDatabaseForUri() 3140702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (match == MEDIA_SCANNER) { 3141bc442ef681710cca3d8eb1a57d6e81471c9987c0Mike Lockwood mMediaScannerVolume = initialValues.getAsString(MediaStore.MEDIA_SCANNER_VOLUME); 314210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen DatabaseHelper database = getDatabaseForUri( 314310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen Uri.parse("content://media/" + mMediaScannerVolume + "/audio")); 314410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen if (database == null) { 314510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen Log.w(TAG, "no database for scanned volume " + mMediaScannerVolume); 314610af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen } else { 314710af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen database.mScanStartTime = SystemClock.currentTimeMicro(); 314810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen } 3149702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return MediaStore.getMediaScannerUri(); 3150702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3151702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3152b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood String genre = null; 315338b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen String path = null; 3154b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood if (initialValues != null) { 3155b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood genre = initialValues.getAsString(Audio.AudioColumns.GENRE); 3156b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood initialValues.remove(Audio.AudioColumns.GENRE); 315738b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen path = initialValues.getAsString(MediaStore.MediaColumns.DATA); 3158b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood } 3159b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood 316038b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen 3161702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Uri newUri = null; 316210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen DatabaseHelper helper = getDatabaseForUri(uri); 316310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen if (helper == null && match != VOLUMES && match != MTP_CONNECTED) { 3164702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException( 3165702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Unknown URI: " + uri); 3166702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 316710af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen 3168819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood SQLiteDatabase db = ((match == VOLUMES || match == MTP_CONNECTED) ? null 316910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen : helper.getWritableDatabase()); 3170702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3171702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (match) { 3172702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA: { 317310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen rowId = insertFile(helper, uri, initialValues, FileColumns.MEDIA_TYPE_IMAGE, true); 3174702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 3175702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId( 3176702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Images.Media.getContentUri(uri.getPathSegments().get(0)), rowId); 3177702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3178702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3179702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3180702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3181b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // This will be triggered by requestMediaThumbnail (see getThumbnailUri) 3182702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_THUMBNAILS: { 318310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen ContentValues values = ensureFile(helper.mInternal, initialValues, ".jpg", 3184b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "DCIM/.thumbnails"); 318510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumInserts++; 3186702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert("thumbnails", "name", values); 3187702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 3188702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(Images.Thumbnails. 3189702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContentUri(uri.getPathSegments().get(0)), rowId); 3190702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3191702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3192702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3193702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3194b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // This is currently only used by MICRO_KIND video thumbnail (see getThumbnailUri) 3195b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case VIDEO_THUMBNAILS: { 319610af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen ContentValues values = ensureFile(helper.mInternal, initialValues, ".jpg", 3197b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "DCIM/.thumbnails"); 319810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumInserts++; 3199b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen rowId = db.insert("videothumbnails", "name", values); 3200b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (rowId > 0) { 3201b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen newUri = ContentUris.withAppendedId(Video.Thumbnails. 3202b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen getContentUri(uri.getPathSegments().get(0)), rowId); 3203b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 3204b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen break; 3205b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 3206b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 3207702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA: { 320810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen rowId = insertFile(helper, uri, initialValues, FileColumns.MEDIA_TYPE_AUDIO, true); 3209702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 3210702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(Audio.Media.getContentUri(uri.getPathSegments().get(0)), rowId); 3211b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood if (genre != null) { 3212b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood updateGenre(rowId, genre); 3213b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood } 3214702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3215702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3216702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3217702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3218702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES: { 3219702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Long audioId = Long.parseLong(uri.getPathSegments().get(2)); 3220bc442ef681710cca3d8eb1a57d6e81471c9987c0Mike Lockwood ContentValues values = new ContentValues(initialValues); 3221702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(Audio.Genres.Members.AUDIO_ID, audioId); 322210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumInserts++; 3223ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen rowId = db.insert("audio_genres_map", "genre_id", values); 3224702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 3225702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(uri, rowId); 3226702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3227702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3228702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3229702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3230702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS: { 3231702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Long audioId = Long.parseLong(uri.getPathSegments().get(2)); 3232bc442ef681710cca3d8eb1a57d6e81471c9987c0Mike Lockwood ContentValues values = new ContentValues(initialValues); 3233702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(Audio.Playlists.Members.AUDIO_ID, audioId); 323410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumInserts++; 3235702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert("audio_playlists_map", "playlist_id", 3236702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values); 3237702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 3238702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(uri, rowId); 3239702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3240702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3241702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3242702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3243702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES: { 324410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumInserts++; 3245bc442ef681710cca3d8eb1a57d6e81471c9987c0Mike Lockwood rowId = db.insert("audio_genres", "audio_id", initialValues); 3246702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 3247702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(Audio.Genres.getContentUri(uri.getPathSegments().get(0)), rowId); 3248702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3249702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3250702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3251702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3252702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID_MEMBERS: { 3253702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Long genreId = Long.parseLong(uri.getPathSegments().get(3)); 3254bc442ef681710cca3d8eb1a57d6e81471c9987c0Mike Lockwood ContentValues values = new ContentValues(initialValues); 3255702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(Audio.Genres.Members.GENRE_ID, genreId); 325610af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumInserts++; 3257702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert("audio_genres_map", "genre_id", values); 3258702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 3259702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(uri, rowId); 3260702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3261702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3262702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3263702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3264702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS: { 3265bc442ef681710cca3d8eb1a57d6e81471c9987c0Mike Lockwood ContentValues values = new ContentValues(initialValues); 3266702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(MediaStore.Audio.Playlists.DATE_ADDED, System.currentTimeMillis() / 1000); 326710af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen rowId = insertFile(helper, uri, values, FileColumns.MEDIA_TYPE_PLAYLIST, true); 3268702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 3269702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(Audio.Playlists.getContentUri(uri.getPathSegments().get(0)), rowId); 3270702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3271702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3272702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3273702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3274702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID: 3275702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS: { 3276702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Long playlistId = Long.parseLong(uri.getPathSegments().get(3)); 3277bc442ef681710cca3d8eb1a57d6e81471c9987c0Mike Lockwood ContentValues values = new ContentValues(initialValues); 3278702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(Audio.Playlists.Members.PLAYLIST_ID, playlistId); 327910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumInserts++; 3280ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen rowId = db.insert("audio_playlists_map", "playlist_id", values); 3281702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 3282702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(uri, rowId); 3283702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3284702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3285702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3286702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3287702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA: { 328810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen rowId = insertFile(helper, uri, initialValues, FileColumns.MEDIA_TYPE_VIDEO, true); 3289702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 3290b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen newUri = ContentUris.withAppendedId(Video.Media.getContentUri( 3291b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen uri.getPathSegments().get(0)), rowId); 3292702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3293702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3294702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3295702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3296c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood case AUDIO_ALBUMART: { 329710af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen if (helper.mInternal) { 3298702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException("no internal album art allowed"); 3299702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3300bc442ef681710cca3d8eb1a57d6e81471c9987c0Mike Lockwood ContentValues values = null; 3301702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 3302bc442ef681710cca3d8eb1a57d6e81471c9987c0Mike Lockwood values = ensureFile(false, initialValues, "", ALBUM_THUMB_FOLDER); 3303702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } catch (IllegalStateException ex) { 3304702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // probably no more room to store albumthumbs 3305bc442ef681710cca3d8eb1a57d6e81471c9987c0Mike Lockwood values = initialValues; 3306702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 330710af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumInserts++; 3308801ba04ac37ee06dccb8bf4081b29a162795e3a6Mike Lockwood rowId = db.insert("album_art", MediaStore.MediaColumns.DATA, values); 3309702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 3310702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(uri, rowId); 3311702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3312702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3313c198bd976a754d94863d1b50fe392376ded122a0Mike Lockwood } 3314702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3315702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VOLUMES: 33165619dbb4338e9acea165f4cc0f1791d00e8df445Marco Nelissen { 33175619dbb4338e9acea165f4cc0f1791d00e8df445Marco Nelissen String name = initialValues.getAsString("name"); 33185619dbb4338e9acea165f4cc0f1791d00e8df445Marco Nelissen Uri attachedVolume = attachVolume(name); 33195619dbb4338e9acea165f4cc0f1791d00e8df445Marco Nelissen if (mMediaScannerVolume != null && mMediaScannerVolume.equals(name)) { 33205619dbb4338e9acea165f4cc0f1791d00e8df445Marco Nelissen DatabaseHelper dbhelper = getDatabaseForUri(attachedVolume); 33215619dbb4338e9acea165f4cc0f1791d00e8df445Marco Nelissen if (dbhelper == null) { 33225619dbb4338e9acea165f4cc0f1791d00e8df445Marco Nelissen Log.e(TAG, "no database for attached volume " + attachedVolume); 33235619dbb4338e9acea165f4cc0f1791d00e8df445Marco Nelissen } else { 33245619dbb4338e9acea165f4cc0f1791d00e8df445Marco Nelissen dbhelper.mScanStartTime = SystemClock.currentTimeMicro(); 33255619dbb4338e9acea165f4cc0f1791d00e8df445Marco Nelissen } 33265619dbb4338e9acea165f4cc0f1791d00e8df445Marco Nelissen } 33275619dbb4338e9acea165f4cc0f1791d00e8df445Marco Nelissen return attachedVolume; 33285619dbb4338e9acea165f4cc0f1791d00e8df445Marco Nelissen } 3329702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3330819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood case MTP_CONNECTED: 333134be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood synchronized (mMtpServiceConnection) { 333234be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood if (mMtpService == null) { 333334be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood Context context = getContext(); 333434be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood // MTP is connected, so grab a connection to MtpService 333534be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood context.bindService(new Intent(context, MtpService.class), 333634be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood mMtpServiceConnection, Context.BIND_AUTO_CREATE); 333734be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood } 333834be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood } 3339819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood break; 3340819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood 3341afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood case FILES: 334210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen rowId = insertFile(helper, uri, initialValues, 3343bc442ef681710cca3d8eb1a57d6e81471c9987c0Mike Lockwood FileColumns.MEDIA_TYPE_NONE, true); 3344fc824ed365b03ae272a3241b202367b1bdec18bcMike Lockwood if (rowId > 0) { 3345fc824ed365b03ae272a3241b202367b1bdec18bcMike Lockwood newUri = Files.getContentUri(uri.getPathSegments().get(0), rowId); 3346fc824ed365b03ae272a3241b202367b1bdec18bcMike Lockwood } 3347fc824ed365b03ae272a3241b202367b1bdec18bcMike Lockwood break; 3348fc824ed365b03ae272a3241b202367b1bdec18bcMike Lockwood 3349e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood case MTP_OBJECTS: 3350afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood // don't send a notification if the insert originated from MTP 335110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen rowId = insertFile(helper, uri, initialValues, 3352bc442ef681710cca3d8eb1a57d6e81471c9987c0Mike Lockwood FileColumns.MEDIA_TYPE_NONE, false); 3353afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood if (rowId > 0) { 3354afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood newUri = Files.getMtpObjectsUri(uri.getPathSegments().get(0), rowId); 33555d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood } 33565d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood break; 33575d7e71a87b085817aef6e77cd4c2a6dc7d983f9fMike Lockwood 3358702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project default: 3359702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException("Invalid URI " + uri); 3360702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3361702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 336238b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen if (path != null && path.toLowerCase(Locale.US).endsWith("/.nomedia")) { 336338b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen // need to set the media_type of all the files below this folder to 0 336438b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen processNewNoMediaPath(helper, db, path); 336538b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen } 3366702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return newUri; 3367702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3368702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 336938b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen /* 337038b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen * Sets the media type of all files below the newly added .nomedia file or 337138b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen * hidden folder to 0, so the entries no longer appear in e.g. the audio and 337238b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen * images views. 337338b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen * 337438b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen * @param path The path to the new .nomedia file or hidden directory 337538b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen */ 337638b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen private void processNewNoMediaPath(DatabaseHelper helper, SQLiteDatabase db, String path) { 337738b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen File nomedia = new File(path); 337838b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen if (nomedia.exists()) { 337938b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen // only do this if the file actually exists, so we don't get tricked 338038b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen // by someone just inserting a .nomedia entry into the database 338138b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen String hiddenroot = nomedia.isDirectory() ? path : nomedia.getParent(); 338238b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen ContentValues mediatype = new ContentValues(); 338338b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen mediatype.put("media_type", 0); 338438b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen int numrows = db.update("files", mediatype, "_data LIKE ?", new String[] { hiddenroot + "/%"}); 338538b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen helper.mNumUpdates += numrows; 338638b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen ContentResolver res = getContext().getContentResolver(); 338738b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen res.notifyChange(Uri.parse("content://media/"), null); 338838b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen } 338938b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen } 339038b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen 339138b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen /* 339238b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen * Rescan files for missing metadata and set their type accordingly. 339338b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen * There is code for detecting the removal of a nomedia file or renaming of 339438b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen * a directory from hidden to non-hidden in the MediaScanner and MtpDatabase, 339538b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen * both of which call here. 339638b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen */ 339738b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen private void processRemovedNoMediaPath(final String path) { 339838b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen final DatabaseHelper helper; 339938b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen if (path.startsWith(mExternalStoragePaths[0])) { 340038b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen helper = getDatabaseForUri(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI); 340138b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen } else { 340238b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen helper = getDatabaseForUri(MediaStore.Audio.Media.INTERNAL_CONTENT_URI); 340338b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen } 340438b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen SQLiteDatabase db = helper.getWritableDatabase(); 340538b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen new ScannerClient(getContext(), db, path); 340638b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen } 340738b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen 340838b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen private static final class ScannerClient implements MediaScannerConnectionClient { 340938b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen String mPath = null; 341038b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen MediaScannerConnection mScannerConnection; 341138b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen SQLiteDatabase mDb; 341238b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen 341338b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen public ScannerClient(Context context, SQLiteDatabase db, String path) { 341438b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen mDb = db; 341538b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen mPath = path; 341638b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen mScannerConnection = new MediaScannerConnection(context, this); 341738b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen mScannerConnection.connect(); 341838b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen } 341938b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen 342038b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen @Override 342138b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen public void onMediaScannerConnected() { 342238b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen Cursor c = mDb.query("files", openFileColumns, "_data like ?", 342338b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen new String[] { mPath + "/%"}, null, null, null); 342438b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen while (c.moveToNext()) { 342538b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen String d = c.getString(0); 342638b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen File f = new File(d); 342738b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen if (f.isFile()) { 342838b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen mScannerConnection.scanFile(d, null); 342938b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen } 343038b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen } 343138b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen mScannerConnection.disconnect(); 343238b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen c.close(); 343338b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen } 343438b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen 343538b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen @Override 343638b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen public void onScanCompleted(String path, Uri uri) { 343738b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen } 343838b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen } 343938b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen 3440cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen @Override 3441cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) 3442cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen throws OperationApplicationException { 3443cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen 3444cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen // The operations array provides no overall information about the URI(s) being operated 3445cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen // on, so begin a transaction for ALL of the databases. 3446cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen DatabaseHelper ihelper = getDatabaseForUri(MediaStore.Audio.Media.INTERNAL_CONTENT_URI); 3447cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen DatabaseHelper ehelper = getDatabaseForUri(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI); 3448cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen SQLiteDatabase idb = ihelper.getWritableDatabase(); 3449cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen idb.beginTransaction(); 3450cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen SQLiteDatabase edb = null; 3451cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen if (ehelper != null) { 3452cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen edb = ehelper.getWritableDatabase(); 3453cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen edb.beginTransaction(); 3454cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen } 3455cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen try { 3456cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen ContentProviderResult[] result = super.applyBatch(operations); 3457cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen idb.setTransactionSuccessful(); 3458cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen if (edb != null) { 3459cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen edb.setTransactionSuccessful(); 3460cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen } 3461cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen // Rather than sending targeted change notifications for every Uri 3462cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen // affected by the batch operation, just invalidate the entire internal 3463cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen // and external name space. 3464cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen ContentResolver res = getContext().getContentResolver(); 3465cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen res.notifyChange(Uri.parse("content://media/"), null); 3466cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen return result; 3467cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen } finally { 3468cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen idb.endTransaction(); 3469cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen if (edb != null) { 3470cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen edb.endTransaction(); 3471cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen } 3472cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen } 3473cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen } 3474cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen 3475cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen 34769299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen private MediaThumbRequest requestMediaThumbnail(String path, Uri uri, int priority, long magic) { 3477b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen synchronized (mMediaThumbQueue) { 3478e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen MediaThumbRequest req = null; 3479e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen try { 3480e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen req = new MediaThumbRequest( 34819299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen getContext().getContentResolver(), path, uri, priority, magic); 3482e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen mMediaThumbQueue.add(req); 3483e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen // Trigger the handler. 3484e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen Message msg = mThumbHandler.obtainMessage(IMAGE_THUMB); 3485e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen msg.sendToTarget(); 3486e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen } catch (Throwable t) { 3487e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen Log.w(TAG, t); 3488e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen } 3489b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return req; 3490b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 3491b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 3492b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 3493702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private String generateFileName(boolean internal, String preferredExtension, String directoryName) 3494702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project { 3495702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // create a random file 3496702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String name = String.valueOf(System.currentTimeMillis()); 3497702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3498702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (internal) { 3499702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException("Writing to internal storage is not supported."); 3500702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project// return Environment.getDataDirectory() 3501702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project// + "/" + directoryName + "/" + name + preferredExtension; 3502702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 35039be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood return mExternalStoragePaths[0] + "/" + directoryName + "/" + name + preferredExtension; 3504702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3505702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3506702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3507702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private boolean ensureFileExists(String path) { 3508702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File file = new File(path); 3509702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (file.exists()) { 3510702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return true; 3511702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 3512702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // we will not attempt to create the first directory in the path 3513702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // (for example, do not create /sdcard if the SD card is not mounted) 3514702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int secondSlash = path.indexOf('/', 1); 3515702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (secondSlash < 1) return false; 3516702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String directoryPath = path.substring(0, secondSlash); 3517702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File directory = new File(directoryPath); 3518702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!directory.exists()) 3519702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return false; 352017ad80b32f839ccddac3911799ff732d1ca3a006Mike Lockwood file.getParentFile().mkdirs(); 3521702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 352217ad80b32f839ccddac3911799ff732d1ca3a006Mike Lockwood return file.createNewFile(); 3523702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } catch(IOException ioe) { 3524702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Log.e(TAG, "File creation failed", ioe); 3525702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3526702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return false; 3527702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3528702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3529702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3530702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final class GetTableAndWhereOutParameter { 3531702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public String table; 3532702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public String where; 3533702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3534702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3535702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project static final GetTableAndWhereOutParameter sGetTableAndWhereParam = 3536702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project new GetTableAndWhereOutParameter(); 3537702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3538702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private void getTableAndWhere(Uri uri, int match, String userWhere, 3539702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project GetTableAndWhereOutParameter out) { 3540702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String where = null; 3541702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (match) { 35429f02f449f6951b15bb9daaa3fc6e1d648b36b08aGoodwin case IMAGES_MEDIA: 3543afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood out.table = "files"; 3544afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood where = FileColumns.MEDIA_TYPE + "=" + FileColumns.MEDIA_TYPE_IMAGE; 35459f02f449f6951b15bb9daaa3fc6e1d648b36b08aGoodwin break; 35469f02f449f6951b15bb9daaa3fc6e1d648b36b08aGoodwin 3547702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA_ID: 3548afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood out.table = "files"; 3549702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "_id = " + uri.getPathSegments().get(3); 3550702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3551702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3552b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case IMAGES_THUMBNAILS_ID: 3553b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen where = "_id=" + uri.getPathSegments().get(3); 3554b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case IMAGES_THUMBNAILS: 3555b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen out.table = "thumbnails"; 3556b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen break; 3557b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 3558702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA: 3559afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood out.table = "files"; 3560afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood where = FileColumns.MEDIA_TYPE + "=" + FileColumns.MEDIA_TYPE_AUDIO; 3561702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3562702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3563702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID: 3564afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood out.table = "files"; 3565702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "_id=" + uri.getPathSegments().get(3); 3566702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3567702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3568702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES: 3569702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_genres"; 3570702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "audio_id=" + uri.getPathSegments().get(3); 3571702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3572702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3573702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES_ID: 3574702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_genres"; 3575702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "audio_id=" + uri.getPathSegments().get(3) + 3576702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " AND genre_id=" + uri.getPathSegments().get(5); 3577702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3578702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3579702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS: 3580702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_playlists"; 3581702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "audio_id=" + uri.getPathSegments().get(3); 3582702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3583702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3584702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS_ID: 3585702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_playlists"; 3586702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "audio_id=" + uri.getPathSegments().get(3) + 3587702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " AND playlists_id=" + uri.getPathSegments().get(5); 3588702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3589702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3590702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES: 3591702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_genres"; 3592702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3593702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3594702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID: 3595702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_genres"; 3596702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "_id=" + uri.getPathSegments().get(3); 3597702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3598702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3599702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID_MEMBERS: 3600702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_genres"; 3601702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "genre_id=" + uri.getPathSegments().get(3); 3602702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3603702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3604702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS: 3605afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood out.table = "files"; 3606afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood where = FileColumns.MEDIA_TYPE + "=" + FileColumns.MEDIA_TYPE_PLAYLIST; 3607702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3608702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3609702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID: 3610afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood out.table = "files"; 3611702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "_id=" + uri.getPathSegments().get(3); 3612702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3613702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3614702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS: 3615702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_playlists_map"; 3616702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "playlist_id=" + uri.getPathSegments().get(3); 3617702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3618702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3619702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS_ID: 3620702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_playlists_map"; 3621702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "playlist_id=" + uri.getPathSegments().get(3) + 3622702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " AND _id=" + uri.getPathSegments().get(5); 3623702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3624702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3625702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ALBUMART_ID: 3626702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "album_art"; 3627702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "album_id=" + uri.getPathSegments().get(3); 3628702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3629702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3630702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA: 3631afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood out.table = "files"; 3632afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood where = FileColumns.MEDIA_TYPE + "=" + FileColumns.MEDIA_TYPE_VIDEO; 3633702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3634702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3635702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA_ID: 3636afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood out.table = "files"; 3637702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "_id=" + uri.getPathSegments().get(3); 3638702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3639702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3640b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case VIDEO_THUMBNAILS_ID: 3641b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen where = "_id=" + uri.getPathSegments().get(3); 3642b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case VIDEO_THUMBNAILS: 3643b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen out.table = "videothumbnails"; 3644b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen break; 3645b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 364616dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood case FILES_ID: 3647e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood case MTP_OBJECTS_ID: 36481717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood where = "_id=" + uri.getPathSegments().get(2); 364916dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood case FILES: 3650e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood case MTP_OBJECTS: 365116dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood out.table = "files"; 36521717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood break; 36531717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood 3654702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project default: 3655702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException( 3656702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Unknown or unsupported URL: " + uri.toString()); 3657702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3658702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3659702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Add in the user requested WHERE clause, if needed 3660702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!TextUtils.isEmpty(userWhere)) { 3661702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!TextUtils.isEmpty(where)) { 3662702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.where = where + " AND (" + userWhere + ")"; 3663702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 3664702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.where = userWhere; 3665702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3666702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 3667702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.where = where; 3668702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3669702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3670702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3671702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 3672702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public int delete(Uri uri, String userWhere, String[] whereArgs) { 3673702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int count; 3674702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int match = URI_MATCHER.match(uri); 3675702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3676702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // handle MEDIA_SCANNER before calling getDatabaseForUri() 3677702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (match == MEDIA_SCANNER) { 3678702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (mMediaScannerVolume == null) { 3679702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return 0; 3680702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 368110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen DatabaseHelper database = getDatabaseForUri( 368210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen Uri.parse("content://media/" + mMediaScannerVolume + "/audio")); 368310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen if (database == null) { 368410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen Log.w(TAG, "no database for scanned volume " + mMediaScannerVolume); 368510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen } else { 368610af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen database.mScanStopTime = SystemClock.currentTimeMicro(); 3687988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen String msg = dump(database, false); 3688988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen logToDb(database.getWritableDatabase(), msg); 368910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen } 3690702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mMediaScannerVolume = null; 3691702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return 1; 3692702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3693702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3694819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood if (match == VOLUMES_ID) { 3695819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood detachVolume(uri); 3696819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood count = 1; 3697819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood } else if (match == MTP_CONNECTED) { 369834be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood synchronized (mMtpServiceConnection) { 369934be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood if (mMtpService != null) { 370034be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood // MTP has disconnected, so release our connection to MtpService 370134be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood getContext().unbindService(mMtpServiceConnection); 370234be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood count = 1; 370334be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood // mMtpServiceConnection.onServiceDisconnected might not get called, 370434be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood // so set mMtpService = null here 370534be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood mMtpService = null; 370634be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood } else { 370734be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood count = 0; 370834be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood } 370934be4a25e4374a934ac4627fb5fed06bbf6f72faMike Lockwood } 3710819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood } else { 3711702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DatabaseHelper database = getDatabaseForUri(uri); 3712702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (database == null) { 3713702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException( 3714819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood "Unknown URI: " + uri + " match: " + match); 3715702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 371610af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen database.mNumDeletes++; 3717702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteDatabase db = database.getWritableDatabase(); 3718702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3719702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized (sGetTableAndWhereParam) { 3720702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getTableAndWhere(uri, match, userWhere, sGetTableAndWhereParam); 3721a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen 3722a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen if (sGetTableAndWhereParam.table.equals("files")) { 3723d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen String deleteparam = uri.getQueryParameter(MediaStore.PARAM_DELETE_DATA); 3724d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen if (deleteparam == null || ! deleteparam.equals("false")) { 3725d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen database.mNumQueries++; 3726d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen Cursor c = db.query(sGetTableAndWhereParam.table, 3727d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen sMediaTypeDataId, 3728d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen sGetTableAndWhereParam.where, whereArgs, null, null, null); 3729d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen String [] idvalue = new String[] { "" }; 37304eff7fef57715b2247f9cfc98c7f69809ab35adeMarco Nelissen String [] playlistvalues = new String[] { "", "" }; 3731d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen while (c.moveToNext()) { 3732d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen int mediatype = c.getInt(0); 3733d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen if (mediatype == FileColumns.MEDIA_TYPE_IMAGE) { 3734d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen try { 3735d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen Libcore.os.remove(c.getString(1)); 3736d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen idvalue[0] = "" + c.getLong(2); 3737d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen database.mNumQueries++; 3738d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen Cursor cc = db.query("thumbnails", sDataOnlyColumn, 3739d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen "image_id=?", idvalue, null, null, null); 3740d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen while (cc.moveToNext()) { 3741d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen Libcore.os.remove(cc.getString(0)); 3742d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen } 3743d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen cc.close(); 3744d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen database.mNumDeletes++; 3745d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen db.delete("thumbnails", "image_id=?", idvalue); 3746d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen } catch (ErrnoException e) { 3747a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen } 3748d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen } else if (mediatype == FileColumns.MEDIA_TYPE_VIDEO) { 3749d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen try { 3750d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen Libcore.os.remove(c.getString(1)); 3751d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen } catch (ErrnoException e) { 3752d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen } 3753d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen } else if (mediatype == FileColumns.MEDIA_TYPE_AUDIO) { 3754f0b229bef169b9c7197ec630ef79a36bf5ba9969Marco Nelissen if (!database.mInternal) { 3755f0b229bef169b9c7197ec630ef79a36bf5ba9969Marco Nelissen idvalue[0] = "" + c.getLong(2); 3756f0b229bef169b9c7197ec630ef79a36bf5ba9969Marco Nelissen db.delete("audio_genres_map", "audio_id=?", idvalue); 37574eff7fef57715b2247f9cfc98c7f69809ab35adeMarco Nelissen // for each playlist that the item appears in, move 37584eff7fef57715b2247f9cfc98c7f69809ab35adeMarco Nelissen // all the items behind it forward by one 37594eff7fef57715b2247f9cfc98c7f69809ab35adeMarco Nelissen Cursor cc = db.query("audio_playlists_map", 37604eff7fef57715b2247f9cfc98c7f69809ab35adeMarco Nelissen sPlaylistIdPlayOrder, 37614eff7fef57715b2247f9cfc98c7f69809ab35adeMarco Nelissen "audio_id=?", idvalue, null, null, null); 37624eff7fef57715b2247f9cfc98c7f69809ab35adeMarco Nelissen while (cc.moveToNext()) { 37634eff7fef57715b2247f9cfc98c7f69809ab35adeMarco Nelissen playlistvalues[0] = "" + cc.getLong(0); 37644eff7fef57715b2247f9cfc98c7f69809ab35adeMarco Nelissen playlistvalues[1] = "" + cc.getInt(1); 37654eff7fef57715b2247f9cfc98c7f69809ab35adeMarco Nelissen db.execSQL("UPDATE audio_playlists_map" + 37664eff7fef57715b2247f9cfc98c7f69809ab35adeMarco Nelissen " SET play_order=play_order-1" + 37674eff7fef57715b2247f9cfc98c7f69809ab35adeMarco Nelissen " WHERE playlist_id=? AND play_order>?", 37684eff7fef57715b2247f9cfc98c7f69809ab35adeMarco Nelissen playlistvalues); 37694eff7fef57715b2247f9cfc98c7f69809ab35adeMarco Nelissen } 37704eff7fef57715b2247f9cfc98c7f69809ab35adeMarco Nelissen cc.close(); 3771f0b229bef169b9c7197ec630ef79a36bf5ba9969Marco Nelissen db.delete("audio_playlists_map", "audio_id=?", idvalue); 3772f0b229bef169b9c7197ec630ef79a36bf5ba9969Marco Nelissen } 3773d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen } else if (mediatype == FileColumns.MEDIA_TYPE_PLAYLIST) { 3774d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen // TODO, maybe: remove the audio_playlists_cleanup trigger and implement 3775d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen // it functionality here (clean up the playlist map) 37765afff430a4ebb751dadeb0112a1fe2052c6f5c05Marco Nelissen } 3777a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen } 3778d1983eb3406c26342fd5da4657e819a905fd4bebMarco Nelissen c.close(); 3779a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen } 3780a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen } 3781a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen 3782702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (match) { 378336339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood case MTP_OBJECTS: 3784e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood case MTP_OBJECTS_ID: 3785d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood try { 3786d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood // don't send objectRemoved event since this originated from MTP 3787d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood mDisableMtpObjectCallbacks = true; 378810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen database.mNumDeletes++; 378910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen count = db.delete("files", sGetTableAndWhereParam.where, whereArgs); 3790d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } finally { 3791d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood mDisableMtpObjectCallbacks = false; 3792d186c64cdd590e6491ee46dd8fcd52600d2edc5cMike Lockwood } 379336339ae4a18855b6e26d82db9d3afd26dc6150a1Mike Lockwood break; 379478b2885edc406273d688536b0eadfea006b20662Marco Nelissen case AUDIO_GENRES_ID_MEMBERS: 379510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen database.mNumDeletes++; 379678b2885edc406273d688536b0eadfea006b20662Marco Nelissen count = db.delete("audio_genres_map", 379778b2885edc406273d688536b0eadfea006b20662Marco Nelissen sGetTableAndWhereParam.where, whereArgs); 379878b2885edc406273d688536b0eadfea006b20662Marco Nelissen break; 3799166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen 3800a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen case IMAGES_THUMBNAILS_ID: 3801a6207286f6e1cc4a13d44194f25ecfc40796e024Marco Nelissen case IMAGES_THUMBNAILS: 3802166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen case VIDEO_THUMBNAILS_ID: 3803166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen case VIDEO_THUMBNAILS: 3804166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen // Delete the referenced files first. 3805166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen Cursor c = db.query(sGetTableAndWhereParam.table, 3806166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen sDataOnlyColumn, 3807166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen sGetTableAndWhereParam.where, whereArgs, null, null, null); 3808166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen if (c != null) { 3809166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen while (c.moveToNext()) { 3810166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen try { 3811166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen Libcore.os.remove(c.getString(0)); 3812166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen } catch (ErrnoException e) { 3813166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen } 3814166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen } 3815166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen c.close(); 3816166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen } 3817166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen database.mNumDeletes++; 3818166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen count = db.delete(sGetTableAndWhereParam.table, 3819166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen sGetTableAndWhereParam.where, whereArgs); 3820166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen break; 3821166204590e5f58008dbc0b4d3abdfa7ab4619867Marco Nelissen 3822702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project default: 382310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen database.mNumDeletes++; 3824702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count = db.delete(sGetTableAndWhereParam.table, 3825702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sGetTableAndWhereParam.where, whereArgs); 3826702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3827702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 38283631d46b679a64a16918698121916b60d7c86e97Mike Lockwood // Since there are multiple Uris that can refer to the same files 38293631d46b679a64a16918698121916b60d7c86e97Mike Lockwood // and deletes can affect other objects in storage (like subdirectories 38303631d46b679a64a16918698121916b60d7c86e97Mike Lockwood // or playlists) we will notify a change on the entire volume to make 38313631d46b679a64a16918698121916b60d7c86e97Mike Lockwood // sure no listeners miss the notification. 38323631d46b679a64a16918698121916b60d7c86e97Mike Lockwood String volume = uri.getPathSegments().get(0); 38333631d46b679a64a16918698121916b60d7c86e97Mike Lockwood Uri notifyUri = Uri.parse("content://" + MediaStore.AUTHORITY + "/" + volume); 38343631d46b679a64a16918698121916b60d7c86e97Mike Lockwood getContext().getContentResolver().notifyChange(notifyUri, null); 3835702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3836702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3837702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3838702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return count; 3839702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3840702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3841702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 384238b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen public Bundle call(String method, String arg, Bundle extras) { 384338b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen if (MediaStore.UNHIDE_CALL.equals(method)) { 384438b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen processRemovedNoMediaPath(arg); 384538b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen return null; 384638b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen } 384738b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen throw new UnsupportedOperationException("Unsupported call: " + method); 384838b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen } 384938b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen 385038b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen @Override 3851702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public int update(Uri uri, ContentValues initialValues, String userWhere, 3852702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String[] whereArgs) { 3853702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int count; 3854b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // Log.v(TAG, "update for uri="+uri+", initValues="+initialValues); 3855702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int match = URI_MATCHER.match(uri); 385610af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen DatabaseHelper helper = getDatabaseForUri(uri); 385710af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen if (helper == null) { 3858702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException( 3859702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Unknown URI: " + uri); 3860702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 386110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumUpdates++; 386210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen 386310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen SQLiteDatabase db = helper.getWritableDatabase(); 3864702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3865b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood String genre = null; 3866b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood if (initialValues != null) { 3867b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood genre = initialValues.getAsString(Audio.AudioColumns.GENRE); 3868b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood initialValues.remove(Audio.AudioColumns.GENRE); 3869b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood } 3870b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood 3871702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized (sGetTableAndWhereParam) { 3872702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getTableAndWhere(uri, match, userWhere, sGetTableAndWhereParam); 3873702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 38741d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood // special case renaming directories via MTP. 38751d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood // in this case we must update all paths in the database with 38761d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood // the directory name as a prefix 38771d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood if ((match == MTP_OBJECTS || match == MTP_OBJECTS_ID) 38781d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood && initialValues != null && initialValues.size() == 1) { 38791d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood String oldPath = null; 3880801ba04ac37ee06dccb8bf4081b29a162795e3a6Mike Lockwood String newPath = initialValues.getAsString(MediaStore.MediaColumns.DATA); 38817f36494e085c26c69cd5925e54028822025eff29Marco Nelissen mDirectoryCache.remove(newPath); 38821d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood // MtpDatabase will rename the directory first, so we test the new file name 388338b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen File f = new File(newPath); 388438b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen if (newPath != null && f.isDirectory()) { 388510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumQueries++; 38861d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood Cursor cursor = db.query(sGetTableAndWhereParam.table, PATH_PROJECTION, 38871d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood userWhere, whereArgs, null, null, null); 38881d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood try { 38891d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood if (cursor != null && cursor.moveToNext()) { 38901d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood oldPath = cursor.getString(1); 38911d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood } 38921d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood } finally { 38931d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood if (cursor != null) cursor.close(); 38941d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood } 38951d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood if (oldPath != null) { 38967f36494e085c26c69cd5925e54028822025eff29Marco Nelissen mDirectoryCache.remove(oldPath); 38971d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood // first rename the row for the directory 389810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumUpdates++; 38991d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood count = db.update(sGetTableAndWhereParam.table, initialValues, 39001d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood sGetTableAndWhereParam.where, whereArgs); 39011d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood if (count > 0) { 39021d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood // then update the paths of any files and folders contained in the directory. 3903dc025ab2edc8d74170ae54dd33860adcca3ad31cMarco Nelissen Object[] bindArgs = new Object[] {oldPath + "/%", oldPath.length() + 1, newPath}; 390410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumUpdates++; 3905dc025ab2edc8d74170ae54dd33860adcca3ad31cMarco Nelissen db.execSQL("UPDATE files SET _data=?3||SUBSTR(_data, ?2) WHERE _data LIKE ?1;", bindArgs); 39061d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood } 39071d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood 39081d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood if (count > 0 && !db.inTransaction()) { 39091d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood getContext().getContentResolver().notifyChange(uri, null); 39101d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood } 391138b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen if (f.getName().startsWith(".")) { 391238b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen // the new directory name is hidden 391338b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen processNewNoMediaPath(helper, db, newPath); 391438b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen } 39151d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood return count; 39161d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood } 391738b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen } else if (newPath.toLowerCase(Locale.US).endsWith("/.nomedia")) { 391838b4364a731875c8f5a845f7543da3494a5424d0Marco Nelissen processNewNoMediaPath(helper, db, newPath); 39191d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood } 39201d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood } 39211d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood 3922702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (match) { 3923702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA: 3924702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID: 3925702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project { 3926702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(initialValues); 39272658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen String albumartist = values.getAsString(MediaStore.Audio.Media.ALBUM_ARTIST); 39282658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen String compilation = values.getAsString(MediaStore.Audio.Media.COMPILATION); 39292658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen values.remove(MediaStore.Audio.Media.COMPILATION); 393007656cccafca173c6ab54c681a69538dcf0516ddMarco Nelissen 3931702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Insert the artist into the artist table and remove it from 3932702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // the input values 3933a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen String artist = values.getAsString("artist"); 39346006570c27674c47fcea8e674832a715cfd653eaMarco Nelissen values.remove("artist"); 3935a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen if (artist != null) { 3936702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long artistRowId; 393710af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen HashMap<String, Long> artistCache = helper.mArtistCache; 3938702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized(artistCache) { 3939a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen Long temp = artistCache.get(artist); 3940702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (temp == null) { 394110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen artistRowId = getKeyIdForName(helper, db, 394210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen "artists", "artist_key", "artist", 3943acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen artist, artist, null, 0, null, artistCache, uri); 3944702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 3945702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project artistRowId = temp.longValue(); 3946702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3947702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3948702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put("artist_id", Integer.toString((int)artistRowId)); 3949702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3950702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 395159948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // Do the same for the album field. 3952a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen String so = values.getAsString("album"); 39536006570c27674c47fcea8e674832a715cfd653eaMarco Nelissen values.remove("album"); 3954702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (so != null) { 3955801ba04ac37ee06dccb8bf4081b29a162795e3a6Mike Lockwood String path = values.getAsString(MediaStore.MediaColumns.DATA); 395659948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen int albumHash = 0; 39572658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen if (albumartist != null) { 39582658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen albumHash = albumartist.hashCode(); 39592658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen } else if (compilation != null && compilation.equals("1")) { 39602658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen // nothing to do, hash already set 396159948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen } else { 39629289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen if (path == null) { 39639289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen if (match == AUDIO_MEDIA) { 39649289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen Log.w(TAG, "Possible multi row album name update without" 39659289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen + " path could give wrong album key"); 39669289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen } else { 39679289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen //Log.w(TAG, "Specify path to avoid extra query"); 39689289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen Cursor c = query(uri, 39699289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen new String[] { MediaStore.Audio.Media.DATA}, 39709289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen null, null, null); 39719289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen if (c != null) { 39729289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen try { 39739289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen int numrows = c.getCount(); 39749289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen if (numrows == 1) { 39759289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen c.moveToFirst(); 39769289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen path = c.getString(0); 39779289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen } else { 39789289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen Log.e(TAG, "" + numrows + " rows for " + uri); 39799289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen } 39809289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen } finally { 39819289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen c.close(); 39829289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen } 39839289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen } 39849289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen } 39859289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen } 39869289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen if (path != null) { 39879289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen albumHash = path.substring(0, path.lastIndexOf('/')).hashCode(); 39889289cbe6396b92365563206050caf3a5efb1f5c8Marco Nelissen } 398959948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen } 39902658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen 3991702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String s = so.toString(); 3992702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long albumRowId; 399310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen HashMap<String, Long> albumCache = helper.mAlbumCache; 3994702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized(albumCache) { 399559948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen String cacheName = s + albumHash; 399659948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen Long temp = albumCache.get(cacheName); 3997702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (temp == null) { 399810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen albumRowId = getKeyIdForName(helper, db, 399910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen "albums", "album_key", "album", 4000a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen s, cacheName, path, albumHash, artist, albumCache, uri); 4001702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 4002702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project albumRowId = temp.longValue(); 4003702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4004702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4005702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put("album_id", Integer.toString((int)albumRowId)); 4006702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4007702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4008702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // don't allow the title_key field to be updated directly 4009702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.remove("title_key"); 4010702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // If the title field is modified, update the title_key 4011702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project so = values.getAsString("title"); 4012702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (so != null) { 4013702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String s = so.toString(); 4014702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put("title_key", MediaStore.Audio.keyFor(s)); 4015e96c1d9637e89b5f99c7002fd06f7f35a9164849Marco Nelissen // do a final trim of the title, in case it started with the special 4016e96c1d9637e89b5f99c7002fd06f7f35a9164849Marco Nelissen // "sort first" character (ascii \001) 4017e96c1d9637e89b5f99c7002fd06f7f35a9164849Marco Nelissen values.remove("title"); 4018e96c1d9637e89b5f99c7002fd06f7f35a9164849Marco Nelissen values.put("title", s.trim()); 4019702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4020702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 402110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumUpdates++; 4022afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood count = db.update(sGetTableAndWhereParam.table, values, 4023afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood sGetTableAndWhereParam.where, whereArgs); 4024b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood if (genre != null) { 4025b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood if (count == 1 && match == AUDIO_MEDIA_ID) { 4026b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood long rowId = Long.parseLong(uri.getPathSegments().get(3)); 4027b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood updateGenre(rowId, genre); 4028b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood } else { 4029b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood // can't handle genres for bulk update or for non-audio files 4030b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood Log.w(TAG, "ignoring genre in update: count = " 4031b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood + count + " match = " + match); 4032b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood } 4033b8f9b763105fb19dc4d955edc3095a64b94d2a58Mike Lockwood } 4034702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4035702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 4036702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA: 4037702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA_ID: 4038702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA: 4039702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA_ID: 4040702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project { 4041702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(initialValues); 4042702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Don't allow bucket id or display name to be updated directly. 4043702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // The same names are used for both images and table columns, so 4044702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // we use the ImageColumns constants here. 4045702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.remove(ImageColumns.BUCKET_ID); 4046702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.remove(ImageColumns.BUCKET_DISPLAY_NAME); 4047702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // If the data is being modified update the bucket values 4048702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String data = values.getAsString(MediaColumns.DATA); 4049702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (data != null) { 4050702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project computeBucketValues(data, values); 4051702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4052b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen computeTakenTime(values); 405310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumUpdates++; 4054702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count = db.update(sGetTableAndWhereParam.table, values, 4055702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sGetTableAndWhereParam.where, whereArgs); 405601a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen // if this is a request from MediaScanner, DATA should contains file path 405701a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen // we only process update request from media scanner, otherwise the requests 405801a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen // could be duplicate. 405901a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen if (count > 0 && values.getAsString(MediaStore.MediaColumns.DATA) != null) { 406010af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumQueries++; 406101a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen Cursor c = db.query(sGetTableAndWhereParam.table, 406201a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen READY_FLAG_PROJECTION, sGetTableAndWhereParam.where, 406301a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen whereArgs, null, null, null); 4064b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (c != null) { 4065216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen try { 4066216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen while (c.moveToNext()) { 4067216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen long magic = c.getLong(2); 4068216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen if (magic == 0) { 4069216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen requestMediaThumbnail(c.getString(1), uri, 4070216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen MediaThumbRequest.PRIORITY_NORMAL, 0); 4071216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen } 4072b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 4073216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen } finally { 4074216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen c.close(); 4075b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 4076b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 4077b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 4078702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4079702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 4080f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen 4081f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen case AUDIO_PLAYLISTS_ID_MEMBERS_ID: 4082f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen String moveit = uri.getQueryParameter("move"); 4083f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen if (moveit != null) { 4084f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen String key = MediaStore.Audio.Playlists.Members.PLAY_ORDER; 4085f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen if (initialValues.containsKey(key)) { 4086f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen int newpos = initialValues.getAsInteger(key); 4087f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen List <String> segments = uri.getPathSegments(); 4088f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen long playlist = Long.valueOf(segments.get(3)); 4089f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen int oldpos = Integer.valueOf(segments.get(5)); 409010af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen return movePlaylistEntry(helper, db, playlist, oldpos, newpos); 4091f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } 4092f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen throw new IllegalArgumentException("Need to specify " + key + 4093f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " when using 'move' parameter"); 4094f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } 4095f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen // fall through 4096702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project default: 409710af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumUpdates++; 4098702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count = db.update(sGetTableAndWhereParam.table, initialValues, 4099702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sGetTableAndWhereParam.where, whereArgs); 4100702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 4101702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4102702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4103cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen // in a transaction, the code that began the transaction should be taking 4104cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen // care of notifications once it ends the transaction successfully 4105cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen if (count > 0 && !db.inTransaction()) { 4106702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 4107702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4108702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return count; 4109702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4110702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 411110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen private int movePlaylistEntry(DatabaseHelper helper, SQLiteDatabase db, 411210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen long playlist, int from, int to) { 4113f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen if (from == to) { 4114f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen return 0; 4115f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } 4116f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen db.beginTransaction(); 4117f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen try { 4118f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen int numlines = 0; 411910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumUpdates += 3; 41204eff7fef57715b2247f9cfc98c7f69809ab35adeMarco Nelissen Cursor c = db.query("audio_playlists_map", 41214eff7fef57715b2247f9cfc98c7f69809ab35adeMarco Nelissen new String [] {"play_order" }, 41224eff7fef57715b2247f9cfc98c7f69809ab35adeMarco Nelissen "playlist_id=?", new String[] {"" + playlist}, null, null, "play_order", 41234eff7fef57715b2247f9cfc98c7f69809ab35adeMarco Nelissen from + ",1"); 41244eff7fef57715b2247f9cfc98c7f69809ab35adeMarco Nelissen c.moveToFirst(); 41254eff7fef57715b2247f9cfc98c7f69809ab35adeMarco Nelissen int from_play_order = c.getInt(0); 41264eff7fef57715b2247f9cfc98c7f69809ab35adeMarco Nelissen c.close(); 41274eff7fef57715b2247f9cfc98c7f69809ab35adeMarco Nelissen c = db.query("audio_playlists_map", 41284eff7fef57715b2247f9cfc98c7f69809ab35adeMarco Nelissen new String [] {"play_order" }, 41294eff7fef57715b2247f9cfc98c7f69809ab35adeMarco Nelissen "playlist_id=?", new String[] {"" + playlist}, null, null, "play_order", 41304eff7fef57715b2247f9cfc98c7f69809ab35adeMarco Nelissen to + ",1"); 41314eff7fef57715b2247f9cfc98c7f69809ab35adeMarco Nelissen c.moveToFirst(); 41324eff7fef57715b2247f9cfc98c7f69809ab35adeMarco Nelissen int to_play_order = c.getInt(0); 41334eff7fef57715b2247f9cfc98c7f69809ab35adeMarco Nelissen c.close(); 4134f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen db.execSQL("UPDATE audio_playlists_map SET play_order=-1" + 41354eff7fef57715b2247f9cfc98c7f69809ab35adeMarco Nelissen " WHERE play_order=" + from_play_order + 4136f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " AND playlist_id=" + playlist); 4137f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen // We could just run both of the next two statements, but only one of 4138f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen // of them will actually do anything, so might as well skip the compile 4139f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen // and execute steps. 4140f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen if (from < to) { 4141f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen db.execSQL("UPDATE audio_playlists_map SET play_order=play_order-1" + 41424eff7fef57715b2247f9cfc98c7f69809ab35adeMarco Nelissen " WHERE play_order<=" + to_play_order + 41434eff7fef57715b2247f9cfc98c7f69809ab35adeMarco Nelissen " AND play_order>" + from_play_order + 4144f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " AND playlist_id=" + playlist); 4145f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen numlines = to - from + 1; 4146f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } else { 4147f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen db.execSQL("UPDATE audio_playlists_map SET play_order=play_order+1" + 41484eff7fef57715b2247f9cfc98c7f69809ab35adeMarco Nelissen " WHERE play_order>=" + to_play_order + 41494eff7fef57715b2247f9cfc98c7f69809ab35adeMarco Nelissen " AND play_order<" + from_play_order + 4150f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " AND playlist_id=" + playlist); 4151f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen numlines = from - to + 1; 4152f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } 41534eff7fef57715b2247f9cfc98c7f69809ab35adeMarco Nelissen db.execSQL("UPDATE audio_playlists_map SET play_order=" + to_play_order + 4154f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " WHERE play_order=-1 AND playlist_id=" + playlist); 4155f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen db.setTransactionSuccessful(); 4156f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen Uri uri = MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI 4157f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen .buildUpon().appendEncodedPath(String.valueOf(playlist)).build(); 4158f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen getContext().getContentResolver().notifyChange(uri, null); 4159f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen return numlines; 4160f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } finally { 4161f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen db.endTransaction(); 4162f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } 4163f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } 4164f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen 4165702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final String[] openFileColumns = new String[] { 4166702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.MediaColumns.DATA, 4167702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project }; 4168702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4169702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 4170702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public ParcelFileDescriptor openFile(Uri uri, String mode) 4171702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throws FileNotFoundException { 417271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen 4173702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ParcelFileDescriptor pfd = null; 417471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen 417571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (URI_MATCHER.match(uri) == AUDIO_ALBUMART_FILE_ID) { 417671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // get album art for the specified media file 417771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen DatabaseHelper database = getDatabaseForUri(uri); 417871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (database == null) { 417971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen throw new IllegalStateException("Couldn't open database for " + uri); 418071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 418171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen SQLiteDatabase db = database.getReadableDatabase(); 41825fde670987a55d69442566dcbdb7830d5f1587c6Chih-Chung Chang if (db == null) { 41835fde670987a55d69442566dcbdb7830d5f1587c6Chih-Chung Chang throw new IllegalStateException("Couldn't open database for " + uri); 41845fde670987a55d69442566dcbdb7830d5f1587c6Chih-Chung Chang } 418571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 418671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen int songid = Integer.parseInt(uri.getPathSegments().get(3)); 418771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen qb.setTables("audio_meta"); 418871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen qb.appendWhere("_id=" + songid); 418971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen Cursor c = qb.query(db, 419071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen new String [] { 419171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen MediaStore.Audio.Media.DATA, 419271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen MediaStore.Audio.Media.ALBUM_ID }, 419371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen null, null, null, null, null); 419471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (c.moveToFirst()) { 419571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen String audiopath = c.getString(0); 419671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen int albumid = c.getInt(1); 419771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // Try to get existing album art for this album first, which 419871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // could possibly have been obtained from a different file. 419971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // If that fails, try to get it from this specific file. 420071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen Uri newUri = ContentUris.withAppendedId(ALBUMART_URI, albumid); 420171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen try { 4202007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey pfd = openFileAndEnforcePathPermissionsHelper(newUri, mode); 420371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } catch (FileNotFoundException ex) { 420471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // That didn't work, now try to get it from the specific file 420534fa8b5146353268880de4dcb61bb4fdffc10543Marco Nelissen pfd = getThumb(database, db, audiopath, albumid, null); 420671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 420771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 420871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen c.close(); 420971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen return pfd; 421071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 421171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen 4212702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 4213007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey pfd = openFileAndEnforcePathPermissionsHelper(uri, mode); 4214702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } catch (FileNotFoundException ex) { 421571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (mode.contains("w")) { 421671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // if the file couldn't be created, we shouldn't extract album art 421771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen throw ex; 421871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 421971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen 4220702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (URI_MATCHER.match(uri) == AUDIO_ALBUMART_ID) { 4221702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Tried to open an album art file which does not exist. Regenerate. 4222702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DatabaseHelper database = getDatabaseForUri(uri); 4223702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (database == null) { 4224702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw ex; 4225702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4226702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteDatabase db = database.getReadableDatabase(); 42275fde670987a55d69442566dcbdb7830d5f1587c6Chih-Chung Chang if (db == null) { 42285fde670987a55d69442566dcbdb7830d5f1587c6Chih-Chung Chang throw new IllegalStateException("Couldn't open database for " + uri); 42295fde670987a55d69442566dcbdb7830d5f1587c6Chih-Chung Chang } 4230702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 4231702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int albumid = Integer.parseInt(uri.getPathSegments().get(3)); 423271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen qb.setTables("audio_meta"); 4233702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("album_id=" + albumid); 4234702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Cursor c = qb.query(db, 4235702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project new String [] { 4236702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.Audio.Media.DATA }, 4237a4d7f8a140c9a66bfcb28c5197521db6d62e13beMarco Nelissen null, null, null, null, MediaStore.Audio.Media.TRACK); 423871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (c.moveToFirst()) { 4239702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String audiopath = c.getString(0); 424034fa8b5146353268880de4dcb61bb4fdffc10543Marco Nelissen pfd = getThumb(database, db, audiopath, albumid, uri); 4241702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4242702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project c.close(); 4243702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 424471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (pfd == null) { 424571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen throw ex; 424671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 4247702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4248702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return pfd; 4249702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4250702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4251007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey /** 4252007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey * Return the {@link MediaColumns#DATA} field for the given {@code Uri}. 4253007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey */ 4254007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey private File queryForDataFile(Uri uri) throws FileNotFoundException { 4255007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey final Cursor cursor = query( 4256007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey uri, new String[] { MediaColumns.DATA }, null, null, null); 4257007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey try { 4258007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey switch (cursor.getCount()) { 4259007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey case 0: 4260007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey throw new FileNotFoundException("No entry for " + uri); 4261007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey case 1: 4262007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey if (cursor.moveToFirst()) { 4263007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey return new File(cursor.getString(0)); 4264007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey } else { 4265007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey throw new FileNotFoundException("Unable to read entry for " + uri); 4266007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey } 4267007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey default: 4268007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey throw new FileNotFoundException("Multiple items at " + uri); 4269007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey } 4270007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey } finally { 4271007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey cursor.close(); 4272007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey } 4273007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey } 4274007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey 4275007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey /** 4276007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey * Replacement for {@link #openFileHelper(Uri, String)} which enforces any 4277007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey * permissions applicable to the path before returning. 4278007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey */ 4279007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey private ParcelFileDescriptor openFileAndEnforcePathPermissionsHelper(Uri uri, String mode) 4280007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey throws FileNotFoundException { 4281007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey final int modeBits = ContentResolver.modeToMode(uri, mode); 4282007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey final boolean isWrite = (modeBits & MODE_WRITE_ONLY) != 0; 4283007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey 4284007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey final File file = queryForDataFile(uri); 4285007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey final String path; 4286007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey try { 4287007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey path = file.getCanonicalPath(); 4288007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey } catch (IOException e) { 4289007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey throw new IllegalArgumentException("Unable to resolve canonical path for " + file, e); 4290007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey } 4291007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey 4292007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey if (path.startsWith(sExternalPath)) { 4293007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey getContext().enforceCallingOrSelfPermission( 4294007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey READ_EXTERNAL_STORAGE, "External path: " + path); 4295007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey 4296007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey if (isWrite) { 4297007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey getContext().enforceCallingOrSelfPermission( 4298007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey WRITE_EXTERNAL_STORAGE, "External path: " + path); 4299007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey } 4300007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey } else if (path.startsWith(sCachePath)) { 4301007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey getContext().enforceCallingOrSelfPermission( 4302007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey ACCESS_CACHE_FILESYSTEM, "Cache path: " + path); 4303007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey } 4304007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey 4305007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey return ParcelFileDescriptor.open(file, modeBits); 4306007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey } 4307007645ee2c67b83ffdd90d0e583ec866c60c4614Jeff Sharkey 4308702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private class ThumbData { 430910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen DatabaseHelper helper; 4310702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteDatabase db; 4311702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String path; 4312702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long album_id; 4313702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Uri albumart_uri; 4314702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4315702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 431610af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen private void makeThumbAsync(DatabaseHelper helper, SQLiteDatabase db, 431710af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen String path, long album_id) { 43188a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber synchronized (mPendingThumbs) { 43198a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (mPendingThumbs.contains(path)) { 43208a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // There's already a request to make an album art thumbnail 43218a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // for this audio file in the queue. 43228a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber return; 43238a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 43248a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 43258a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber mPendingThumbs.add(path); 43268a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 43278a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 4328702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ThumbData d = new ThumbData(); 432910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen d.helper = helper; 4330702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project d.db = db; 4331702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project d.path = path; 4332702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project d.album_id = album_id; 4333a9c4e330dacb37cfffa9c00f7da83cafde4accefMarco Nelissen d.albumart_uri = ContentUris.withAppendedId(mAlbumArtBaseUri, album_id); 43348a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 43358a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // Instead of processing thumbnail requests in the order they were 43368a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // received we instead process them stack-based, i.e. LIFO. 43378a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // The idea behind this is that the most recently requested thumbnails 43388a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // are most likely the ones still in the user's view, whereas those 43398a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // requested earlier may have already scrolled off. 43408a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber synchronized (mThumbRequestStack) { 43418a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber mThumbRequestStack.push(d); 43428a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 43438a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 43448a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // Trigger the handler. 4345b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen Message msg = mThumbHandler.obtainMessage(ALBUM_THUMB); 4346702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project msg.sendToTarget(); 4347702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4348702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 43498a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // Extract compressed image data from the audio file itself or, if that fails, 43508a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // look for a file "AlbumArt.jpg" in the containing directory. 43518a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber private static byte[] getCompressedAlbumArt(Context context, String path) { 43528a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber byte[] compressed = null; 4353702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4354702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 4355702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File f = new File(path); 4356702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ParcelFileDescriptor pfd = ParcelFileDescriptor.open(f, 4357702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ParcelFileDescriptor.MODE_READ_ONLY); 4358702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 43598a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber MediaScanner scanner = new MediaScanner(context); 43608a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber compressed = scanner.extractAlbumArt(pfd.getFileDescriptor()); 4361702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project pfd.close(); 4362702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4363d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // If no embedded art exists, look for a suitable image file in the 43643f9c37ea95a3bdf5f84dc79eb199256c4deda29aMarco Nelissen // same directory as the media file, except if that directory is 43653f9c37ea95a3bdf5f84dc79eb199256c4deda29aMarco Nelissen // is the root directory of the sd card or the download directory. 4366d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // We look for, in order of preference: 4367d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // 0 AlbumArt.jpg 4368d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // 1 AlbumArt*Large.jpg 4369d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // 2 Any other jpg image with 'albumart' anywhere in the name 4370d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // 3 Any other jpg image 4371d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // 4 any other png image 43728a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (compressed == null && path != null) { 4373702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int lastSlash = path.lastIndexOf('/'); 4374702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (lastSlash > 0) { 4375d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen 43763f9c37ea95a3bdf5f84dc79eb199256c4deda29aMarco Nelissen String artPath = path.substring(0, lastSlash); 43779be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood String sdroot = mExternalStoragePaths[0]; 43780fe3097230b324e65a874bd7c8c0f430d2fb8cbeMarco Nelissen String dwndir = Environment.getExternalStoragePublicDirectory( 43792f07f572bc574b685b491ee07a6209c7f2dcb13fMarco Nelissen Environment.DIRECTORY_DOWNLOADS).getAbsolutePath(); 4380d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen 4381d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen String bestmatch = null; 4382d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen synchronized (sFolderArtMap) { 4383d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen if (sFolderArtMap.containsKey(artPath)) { 4384d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = sFolderArtMap.get(artPath); 4385ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen } else if (!artPath.equalsIgnoreCase(sdroot) && 4386ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen !artPath.equalsIgnoreCase(dwndir)) { 4387d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen File dir = new File(artPath); 4388d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen String [] entrynames = dir.list(); 4389d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen if (entrynames == null) { 4390d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen return null; 4391d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } 4392d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = null; 4393d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen int matchlevel = 1000; 4394d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen for (int i = entrynames.length - 1; i >=0; i--) { 4395d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen String entry = entrynames[i].toLowerCase(); 4396d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen if (entry.equals("albumart.jpg")) { 4397d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = entrynames[i]; 4398d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen break; 4399d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } else if (entry.startsWith("albumart") 4400d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen && entry.endsWith("large.jpg") 4401d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen && matchlevel > 1) { 4402d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = entrynames[i]; 4403d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen matchlevel = 1; 4404d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } else if (entry.contains("albumart") 4405d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen && entry.endsWith(".jpg") 4406d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen && matchlevel > 2) { 4407d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = entrynames[i]; 4408d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen matchlevel = 2; 4409d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } else if (entry.endsWith(".jpg") && matchlevel > 3) { 4410d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = entrynames[i]; 4411d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen matchlevel = 3; 4412d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } else if (entry.endsWith(".png") && matchlevel > 4) { 4413d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = entrynames[i]; 4414d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen matchlevel = 4; 4415d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } 4416d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } 4417d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // note that this may insert null if no album art was found 4418d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen sFolderArtMap.put(artPath, bestmatch); 4419d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } 4420d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } 4421d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen 4422d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen if (bestmatch != null) { 44233f9c37ea95a3bdf5f84dc79eb199256c4deda29aMarco Nelissen File file = new File(artPath, bestmatch); 4424d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen if (file.exists()) { 4425d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen compressed = new byte[(int)file.length()]; 4426d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen FileInputStream stream = null; 4427d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen try { 4428d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen stream = new FileInputStream(file); 4429d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen stream.read(compressed); 4430d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } catch (IOException ex) { 4431d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen compressed = null; 4432d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } finally { 4433d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen if (stream != null) { 4434d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen stream.close(); 4435d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } 4436702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4437702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4438702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4439702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4440702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 44418a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } catch (IOException e) { 44428a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 4443702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 44448a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber return compressed; 44458a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 4446702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 44478a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // Return a URI to write the album art to and update the database as necessary. 444810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen Uri getAlbumArtOutputUri(DatabaseHelper helper, SQLiteDatabase db, long album_id, Uri albumart_uri) { 44498a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber Uri out = null; 44508a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // TODO: this could be done more efficiently with a call to db.replace(), which 44518a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // replaces or inserts as needed, making it unnecessary to query() first. 44528a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (albumart_uri != null) { 4453801ba04ac37ee06dccb8bf4081b29a162795e3a6Mike Lockwood Cursor c = query(albumart_uri, new String [] { MediaStore.MediaColumns.DATA }, 44548a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber null, null, null); 4455d8c100241c1c8983deeae6329111e2bce997294dJoakim Johansson try { 4456d8c100241c1c8983deeae6329111e2bce997294dJoakim Johansson if (c != null && c.moveToFirst()) { 4457d8c100241c1c8983deeae6329111e2bce997294dJoakim Johansson String albumart_path = c.getString(0); 4458d8c100241c1c8983deeae6329111e2bce997294dJoakim Johansson if (ensureFileExists(albumart_path)) { 4459d8c100241c1c8983deeae6329111e2bce997294dJoakim Johansson out = albumart_uri; 4460d8c100241c1c8983deeae6329111e2bce997294dJoakim Johansson } 4461d8c100241c1c8983deeae6329111e2bce997294dJoakim Johansson } else { 4462d8c100241c1c8983deeae6329111e2bce997294dJoakim Johansson albumart_uri = null; 4463d8c100241c1c8983deeae6329111e2bce997294dJoakim Johansson } 4464d8c100241c1c8983deeae6329111e2bce997294dJoakim Johansson } finally { 4465d8c100241c1c8983deeae6329111e2bce997294dJoakim Johansson if (c != null) { 4466d8c100241c1c8983deeae6329111e2bce997294dJoakim Johansson c.close(); 4467702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4468702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 446971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 447071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (albumart_uri == null){ 44718a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber ContentValues initialValues = new ContentValues(); 44728a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber initialValues.put("album_id", album_id); 44738a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber try { 44748a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber ContentValues values = ensureFile(false, initialValues, "", ALBUM_THUMB_FOLDER); 447510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumInserts++; 4476801ba04ac37ee06dccb8bf4081b29a162795e3a6Mike Lockwood long rowId = db.insert("album_art", MediaStore.MediaColumns.DATA, values); 44778a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (rowId > 0) { 44788a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber out = ContentUris.withAppendedId(ALBUMART_URI, rowId); 4479702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 44808a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } catch (IllegalStateException ex) { 44818a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber Log.e(TAG, "error creating album thumb file"); 44828a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 44838a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 44848a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber return out; 44858a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 44868a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 44878a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // Write out the album art to the output URI, recompresses the given Bitmap 44888a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // if necessary, otherwise writes the compressed data. 44898a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber private void writeAlbumArt( 44908a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber boolean need_to_recompress, Uri out, byte[] compressed, Bitmap bm) { 44918a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber boolean success = false; 44928a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber try { 44938a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber OutputStream outstream = getContext().getContentResolver().openOutputStream(out); 44948a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 44958a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (!need_to_recompress) { 44968a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // No need to recompress here, just write out the original 44978a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // compressed data here. 44988a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber outstream.write(compressed); 44998a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber success = true; 45008a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } else { 450170676508bd3a081edd909875e141f2c48d79c1acDaniel Lehmann success = bm.compress(Bitmap.CompressFormat.JPEG, 85, outstream); 4502702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 45038a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 45048a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber outstream.close(); 45058a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } catch (FileNotFoundException ex) { 45068a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber Log.e(TAG, "error creating file", ex); 4507702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } catch (IOException ex) { 45088a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber Log.e(TAG, "error creating file", ex); 45098a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 45108a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (!success) { 45118a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // the thumbnail was not written successfully, delete the entry that refers to it 45128a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber getContext().getContentResolver().delete(out, null, null); 4513702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 45148a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 45158a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 451634fa8b5146353268880de4dcb61bb4fdffc10543Marco Nelissen private ParcelFileDescriptor getThumb(DatabaseHelper helper, SQLiteDatabase db, String path, 451734fa8b5146353268880de4dcb61bb4fdffc10543Marco Nelissen long album_id, Uri albumart_uri) { 451871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen ThumbData d = new ThumbData(); 451934fa8b5146353268880de4dcb61bb4fdffc10543Marco Nelissen d.helper = helper; 452071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen d.db = db; 452171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen d.path = path; 452271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen d.album_id = album_id; 452371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen d.albumart_uri = albumart_uri; 452471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen return makeThumbInternal(d); 452571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 452671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen 452771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen private ParcelFileDescriptor makeThumbInternal(ThumbData d) { 45288a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber byte[] compressed = getCompressedAlbumArt(getContext(), d.path); 4529702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 45308a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (compressed == null) { 453171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen return null; 45328a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 45338a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 45348a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber Bitmap bm = null; 45358a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber boolean need_to_recompress = true; 45368a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 45378a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber try { 45388a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // get the size of the bitmap 45398a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber BitmapFactory.Options opts = new BitmapFactory.Options(); 45408a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.inJustDecodeBounds = true; 45418a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.inSampleSize = 1; 45428a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber BitmapFactory.decodeByteArray(compressed, 0, compressed.length, opts); 45438a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 45448a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // request a reasonably sized output image 454570676508bd3a081edd909875e141f2c48d79c1acDaniel Lehmann final Resources r = getContext().getResources(); 454670676508bd3a081edd909875e141f2c48d79c1acDaniel Lehmann final int maximumThumbSize = r.getDimensionPixelSize(R.dimen.maximum_thumb_size); 454770676508bd3a081edd909875e141f2c48d79c1acDaniel Lehmann while (opts.outHeight > maximumThumbSize || opts.outWidth > maximumThumbSize) { 45488a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.outHeight /= 2; 45498a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.outWidth /= 2; 45508a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.inSampleSize *= 2; 45518a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 45528a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 45538a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (opts.inSampleSize == 1) { 45548a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // The original album art was of proper size, we won't have to 45558a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // recompress the bitmap later. 45568a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber need_to_recompress = false; 45578a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } else { 45588a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // get the image for real now 45598a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.inJustDecodeBounds = false; 45608a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.inPreferredConfig = Bitmap.Config.RGB_565; 45618a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber bm = BitmapFactory.decodeByteArray(compressed, 0, compressed.length, opts); 45628a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 45638a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (bm != null && bm.getConfig() == null) { 4564a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen Bitmap nbm = bm.copy(Bitmap.Config.RGB_565, false); 4565a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen if (nbm != null && nbm != bm) { 4566a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen bm.recycle(); 4567a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen bm = nbm; 4568a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen } 45698a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 45708a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 45718a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } catch (Exception e) { 45728a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 45738a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 45748a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (need_to_recompress && bm == null) { 457571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen return null; 45768a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 45778a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 457871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (d.albumart_uri == null) { 457971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // this one doesn't need to be saved (probably a song with an unknown album), 458071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // so stick it in a memory file and return that 458171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen try { 458224001394f571b1f0378840cbf299288e4df10508Bjorn Bringert return ParcelFileDescriptor.fromData(compressed, "albumthumb"); 458371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } catch (IOException e) { 458471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 458571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } else { 4586a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen // This one needs to actually be saved on the sd card. 4587a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen // This is wrapped in a transaction because there are various things 4588a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen // that could go wrong while generating the thumbnail, and we only want 4589a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen // to update the database when all steps succeeded. 4590a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen d.db.beginTransaction(); 4591a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen try { 459210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen Uri out = getAlbumArtOutputUri(d.helper, d.db, d.album_id, d.albumart_uri); 4593a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen 4594a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen if (out != null) { 4595a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen writeAlbumArt(need_to_recompress, out, compressed, bm); 4596a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen getContext().getContentResolver().notifyChange(MEDIA_URI, null); 4597a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen ParcelFileDescriptor pfd = openFileHelper(out, "r"); 4598a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen d.db.setTransactionSuccessful(); 4599a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen return pfd; 4600a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen } 4601a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen } catch (FileNotFoundException ex) { 4602a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen // do nothing, just return null below 4603a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen } catch (UnsupportedOperationException ex) { 4604a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen // do nothing, just return null below 4605a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen } finally { 4606a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen d.db.endTransaction(); 4607a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen if (bm != null) { 4608a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen bm.recycle(); 460971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 461071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 46118a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 461271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen return null; 4613702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4614702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4615702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 4616702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Look up the artist or album entry for the given name, creating that entry 4617702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * if it does not already exists. 4618702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param db The database 4619702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param table The table to store the key/name pair in. 4620702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param keyField The name of the key-column 4621702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param nameField The name of the name-column 4622702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param rawName The name that the calling app was trying to insert into the database 462359948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen * @param cacheName The string that will be inserted in to the cache 462459948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen * @param path The full path to the file being inserted in to the audio table 462559948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen * @param albumHash A hash to distinguish between different albums of the same name 4626a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen * @param artist The name of the artist, if known 4627702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param cache The cache to add this entry to 4628702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param srcuri The Uri that prompted the call to this method, used for determining whether this is 4629702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * the internal or external database 4630702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @return The row ID for this artist/album, or -1 if the provided name was invalid 4631702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 463210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen private long getKeyIdForName(DatabaseHelper helper, SQLiteDatabase db, 463310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen String table, String keyField, String nameField, 463459948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen String rawName, String cacheName, String path, int albumHash, 4635a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen String artist, HashMap<String, Long> cache, Uri srcuri) { 4636702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long rowId; 4637702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4638702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rawName == null || rawName.length() == 0) { 463951cba5e1acf1c56be3dc6c7c46a73a5a0409b452Marco Nelissen rawName = MediaStore.UNKNOWN_STRING; 4640702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4641702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String k = MediaStore.Audio.keyFor(rawName); 4642702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4643702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (k == null) { 464451cba5e1acf1c56be3dc6c7c46a73a5a0409b452Marco Nelissen // shouldn't happen, since we only get null keys for null inputs 464551cba5e1acf1c56be3dc6c7c46a73a5a0409b452Marco Nelissen Log.e(TAG, "null key", new Exception()); 4646702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return -1; 4647702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4648702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 464959948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen boolean isAlbum = table.equals("albums"); 4650e31cfb1a2c21e7ac7a646d40afbb48f49fab6907Marco Nelissen boolean isUnknown = MediaStore.UNKNOWN_STRING.equals(rawName); 465159948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen 46522658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen // To distinguish same-named albums, we append a hash. The hash is based 46532658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen // on the "album artist" tag if present, otherwise on the "compilation" tag 46542658ef46ac41dfd83e385cee5ab96d7f8acbdec5Marco Nelissen // if present, otherwise on the path. 465559948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // Ideally we would also take things like CDDB ID in to account, so 465659948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // we can group files from the same album that aren't in the same 465759948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // folder, but this is a quick and easy start that works immediately 465859948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // without requiring support from the mp3, mp4 and Ogg meta data 465959948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // readers, as long as the albums are in different folders. 4660a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen if (isAlbum) { 466159948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen k = k + albumHash; 4662a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen if (isUnknown) { 4663a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen k = k + artist; 4664a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen } 466559948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen } 466659948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen 4667702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String [] selargs = { k }; 466810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumQueries++; 4669702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Cursor c = db.query(table, null, keyField + "=?", selargs, null, null, null); 4670702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4671702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 4672702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (c.getCount()) { 4673702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case 0: { 4674702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // insert new entry into table 4675702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues otherValues = new ContentValues(); 4676702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project otherValues.put(keyField, k); 4677702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project otherValues.put(nameField, rawName); 467810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumInserts++; 4679702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert(table, "duration", otherValues); 468059948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen if (path != null && isAlbum && ! isUnknown) { 4681702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // We just inserted a new album. Now create an album art thumbnail for it. 468210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen makeThumbAsync(helper, db, path, rowId); 4683702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4684702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 4685702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String volume = srcuri.toString().substring(16, 24); // extract internal/external 4686702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Uri uri = Uri.parse("content://media/" + volume + "/audio/" + table + "/" + rowId); 4687702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 4688702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4689702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4690702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 4691702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case 1: { 4692702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Use the existing entry 4693702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project c.moveToFirst(); 4694702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = c.getLong(0); 4695702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4696702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Determine whether the current rawName is better than what's 4697702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // currently stored in the table, and update the table if it is. 4698702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String currentFancyName = c.getString(2); 4699702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String bestName = makeBestName(rawName, currentFancyName); 4700702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!bestName.equals(currentFancyName)) { 4701702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // update the table with the new name 4702702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues newValues = new ContentValues(); 4703702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newValues.put(nameField, bestName); 470410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper.mNumUpdates++; 4705702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.update(table, newValues, "rowid="+Integer.toString((int)rowId), null); 4706702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String volume = srcuri.toString().substring(16, 24); // extract internal/external 4707702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Uri uri = Uri.parse("content://media/" + volume + "/audio/" + table + "/" + rowId); 4708702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 4709702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4710702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4711702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 4712702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project default: 4713702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // corrupt database 4714702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Log.e(TAG, "Multiple entries in table " + table + " for key " + k); 4715702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = -1; 4716702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 4717702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4718702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 4719702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (c != null) c.close(); 4720702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4721702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 472259948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen if (cache != null && ! isUnknown) { 472359948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen cache.put(cacheName, rowId); 4724702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4725702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return rowId; 4726702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4727702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4728702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 4729702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Returns the best string to use for display, given two names. 4730702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Note that this function does not necessarily return either one 4731702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * of the provided names; it may decide to return a better alternative 4732702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * (for example, specifying the inputs "Police" and "Police, The" will 4733702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * return "The Police") 4734702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 4735702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * The basic assumptions are: 4736702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * - longer is better ("The police" is better than "Police") 4737702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * - prefix is better ("The Police" is better than "Police, The") 4738702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * - accents are better ("Motörhead" is better than "Motorhead") 4739702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 4740702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param one The first of the two names to consider 4741702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param two The last of the two names to consider 4742702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @return The actual name to use 4743702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 4744702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String makeBestName(String one, String two) { 4745702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String name; 4746702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4747702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Longer names are usually better. 4748702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (one.length() > two.length()) { 4749702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project name = one; 4750702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 4751702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Names with accents are usually better, and conveniently sort later 4752702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (one.toLowerCase().compareTo(two.toLowerCase()) > 0) { 4753702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project name = one; 4754702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 4755702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project name = two; 4756702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4757702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4758702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4759702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Prefixes are better than postfixes. 4760702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (name.endsWith(", the") || name.endsWith(",the") || 4761702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project name.endsWith(", an") || name.endsWith(",an") || 4762702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project name.endsWith(", a") || name.endsWith(",a")) { 4763702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String fix = name.substring(1 + name.lastIndexOf(',')); 4764702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project name = fix.trim() + " " + name.substring(0, name.lastIndexOf(',')); 4765702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4766702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4767702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // TODO: word-capitalize the resulting name 4768702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return name; 4769702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4770702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4771702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4772702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 4773702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Looks up the database based on the given URI. 4774702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 4775702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param uri The requested URI 4776702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @returns the database for the given URI 4777702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 4778702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private DatabaseHelper getDatabaseForUri(Uri uri) { 4779702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized (mDatabases) { 47805619dbb4338e9acea165f4cc0f1791d00e8df445Marco Nelissen if (uri.getPathSegments().size() >= 1) { 4781702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return mDatabases.get(uri.getPathSegments().get(0)); 4782702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4783702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4784702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return null; 4785702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4786702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4787fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn static boolean isMediaDatabaseName(String name) { 4788fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn if (INTERNAL_DATABASE_NAME.equals(name)) { 4789fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn return true; 4790fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn } 4791fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn if (EXTERNAL_DATABASE_NAME.equals(name)) { 4792fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn return true; 4793fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn } 4794fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn if (name.startsWith("external-")) { 4795fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn return true; 4796fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn } 4797fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn return false; 4798fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn } 4799fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn 4800fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn static boolean isInternalMediaDatabaseName(String name) { 4801fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn if (INTERNAL_DATABASE_NAME.equals(name)) { 4802fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn return true; 4803fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn } 4804fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn return false; 4805fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn } 4806fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn 4807702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 4808702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Attach the database for a volume (internal or external). 4809702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Does nothing if the volume is already attached, otherwise 4810702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * checks the volume ID and sets up the corresponding database. 4811702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 4812702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param volume to attach, either {@link #INTERNAL_VOLUME} or {@link #EXTERNAL_VOLUME}. 4813702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @return the content URI of the attached volume. 4814702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 4815702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private Uri attachVolume(String volume) { 481675392afde5217038b0c98077758bb9329c2431b2Jeff Brown if (Binder.getCallingPid() != Process.myPid()) { 4817702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new SecurityException( 4818702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Opening and closing databases not allowed."); 4819702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4820702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4821702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized (mDatabases) { 4822702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (mDatabases.get(volume) != null) { // Already attached 4823702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Uri.parse("content://media/" + volume); 4824702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4825702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4826993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood Context context = getContext(); 482710af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen DatabaseHelper helper; 4828702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (INTERNAL_VOLUME.equals(volume)) { 482910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper = new DatabaseHelper(context, INTERNAL_DATABASE_NAME, true, 4830fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn false, mObjectRemovedCallback); 4831702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else if (EXTERNAL_VOLUME.equals(volume)) { 4832993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood if (Environment.isExternalStorageRemovable()) { 48339be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood String path = mExternalStoragePaths[0]; 4834993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood int volumeID = FileUtils.getFatVolumeId(path); 4835993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood if (LOCAL_LOGV) Log.v(TAG, path + " volume ID: " + volumeID); 4836993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood 4837993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood // generate database name based on volume ID 4838993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood String dbName = "external-" + Integer.toHexString(volumeID) + ".db"; 483910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper = new DatabaseHelper(context, dbName, false, 4840fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn false, mObjectRemovedCallback); 4841993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood mVolumeId = volumeID; 4842993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood } else { 4843993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood // external database name should be EXTERNAL_DATABASE_NAME 4844993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood // however earlier releases used the external-XXXXXXXX.db naming 4845993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood // for devices without removable storage, and in that case we need to convert 4846993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood // to this new convention 4847993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood File dbFile = context.getDatabasePath(EXTERNAL_DATABASE_NAME); 4848993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood if (!dbFile.exists()) { 4849993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood // find the most recent external database and rename it to 4850993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood // EXTERNAL_DATABASE_NAME, and delete any other older 4851993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood // external database files 4852993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood File recentDbFile = null; 4853993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood for (String database : context.databaseList()) { 4854993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood if (database.startsWith("external-")) { 4855993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood File file = context.getDatabasePath(database); 4856993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood if (recentDbFile == null) { 4857993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood recentDbFile = file; 4858993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood } else if (file.lastModified() > recentDbFile.lastModified()) { 4859993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood recentDbFile.delete(); 4860993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood recentDbFile = file; 4861993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood } else { 4862993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood file.delete(); 4863993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood } 4864993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood } 4865993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood } 4866993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood if (recentDbFile != null) { 4867993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood if (recentDbFile.renameTo(dbFile)) { 4868993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood Log.d(TAG, "renamed database " + recentDbFile.getName() + 4869993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood " to " + EXTERNAL_DATABASE_NAME); 4870993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood } else { 4871993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood Log.e(TAG, "Failed to rename database " + recentDbFile.getName() + 4872993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood " to " + EXTERNAL_DATABASE_NAME); 4873993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood // This shouldn't happen, but if it does, continue using 4874993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood // the file under its old name 4875993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood dbFile = recentDbFile; 4876993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood } 4877993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood } 4878993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood // else DatabaseHelper will create one named EXTERNAL_DATABASE_NAME 4879993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood } 488010af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen helper = new DatabaseHelper(context, dbFile.getName(), false, 4881fd8402c8904368ad9e90a7fffe4237c87e11273cDianne Hackborn false, mObjectRemovedCallback); 4882993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood } 4883702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 4884702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalArgumentException("There is no volume named " + volume); 4885702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4886702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 488710af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen mDatabases.put(volume, helper); 4888702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 488910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen if (!helper.mInternal) { 4890ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood // create default directories (only happens on first boot) 489110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen createDefaultFolders(helper, helper.getWritableDatabase()); 4892ed9bbc4fa47d545b81248dd749aa0ee4fc598d25Mike Lockwood 4893702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // clean up stray album art files: delete every file not in the database 48949be33f8b8588043b1d104d831fe600a6b7e9d63bMike Lockwood File[] files = new File(mExternalStoragePaths[0], ALBUM_THUMB_FOLDER).listFiles(); 4895702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project HashSet<String> fileSet = new HashSet(); 4896702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project for (int i = 0; files != null && i < files.length; i++) { 4897702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project fileSet.add(files[i].getPath()); 4898702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4899702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4900702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Cursor cursor = query(MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI, 4901702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project new String[] { MediaStore.Audio.Albums.ALBUM_ART }, null, null, null); 4902702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 4903702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project while (cursor != null && cursor.moveToNext()) { 4904702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project fileSet.remove(cursor.getString(0)); 4905702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4906702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 4907702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (cursor != null) cursor.close(); 4908702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4909702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4910702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Iterator<String> iterator = fileSet.iterator(); 4911702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project while (iterator.hasNext()) { 4912702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String filename = iterator.next(); 4913702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (LOCAL_LOGV) Log.v(TAG, "deleting obsolete album art " + filename); 4914702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project new File(filename).delete(); 4915702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4916702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4917702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4918702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4919702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (LOCAL_LOGV) Log.v(TAG, "Attached volume: " + volume); 4920702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Uri.parse("content://media/" + volume); 4921702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4922702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4923702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 4924702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Detach the database for a volume (must be external). 4925702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Does nothing if the volume is already detached, otherwise 4926702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * closes the database and sends a notification to listeners. 4927702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 4928702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param uri The content URI of the volume, as returned by {@link #attachVolume} 4929702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 4930702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private void detachVolume(Uri uri) { 493175392afde5217038b0c98077758bb9329c2431b2Jeff Brown if (Binder.getCallingPid() != Process.myPid()) { 4932702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new SecurityException( 4933702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Opening and closing databases not allowed."); 4934702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4935702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4936702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String volume = uri.getPathSegments().get(0); 4937702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (INTERNAL_VOLUME.equals(volume)) { 4938702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException( 4939702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Deleting the internal volume is not allowed"); 4940702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else if (!EXTERNAL_VOLUME.equals(volume)) { 4941702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalArgumentException( 4942702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "There is no volume named " + volume); 4943702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4944702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4945702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized (mDatabases) { 4946702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DatabaseHelper database = mDatabases.get(volume); 4947702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (database == null) return; 4948702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4949702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 4950702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // touch the database file to show it is most recently used 4951702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File file = new File(database.getReadableDatabase().getPath()); 4952702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project file.setLastModified(System.currentTimeMillis()); 4953e9ee0248d62f3badef8a554f35f78e9116ef8a5cMike Lockwood } catch (Exception e) { 4954702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Log.e(TAG, "Can't touch database file", e); 4955702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4956702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4957702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mDatabases.remove(volume); 4958702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project database.close(); 4959702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4960702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4961702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 4962702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (LOCAL_LOGV) Log.v(TAG, "Detached volume: " + volume); 4963702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 4964702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4965702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static String TAG = "MediaProvider"; 4966ae62a1d602e7ed2e0e30e271bddbb27aa71469f6Christian Mehlmauer private static final boolean LOCAL_LOGV = false; 4967971a2ef5165e2072c76bf25049fdda94187019c2Dianne Hackborn 4968702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final String INTERNAL_DATABASE_NAME = "internal.db"; 4969993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood private static final String EXTERNAL_DATABASE_NAME = "external.db"; 4970702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4971702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // maximum number of cached external databases to keep 4972702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int MAX_EXTERNAL_DATABASES = 3; 4973702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4974702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Delete databases that have not been used in two months 4975702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // 60 days in milliseconds (1000 * 60 * 60 * 24 * 60) 4976702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final long OBSOLETE_DATABASE_DB = 5184000000L; 4977702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4978702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private HashMap<String, DatabaseHelper> mDatabases; 4979702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4980702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private Handler mThumbHandler; 4981702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4982702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // name of the volume currently being scanned by the media scanner (or null) 4983702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private String mMediaScannerVolume; 4984702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 49850027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen // current FAT volume ID 4986993b6f0019bcc3d34f13d73ecef54621b7647d1cMike Lockwood private int mVolumeId = -1; 49870027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen 4988702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project static final String INTERNAL_VOLUME = "internal"; 4989702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project static final String EXTERNAL_VOLUME = "external"; 4990268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen static final String ALBUM_THUMB_FOLDER = "Android/data/com.android.providers.media/albumthumbs"; 4991702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 4992702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // path for writing contents of in memory temp database 4993702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private String mTempDatabasePath; 4994702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 49951717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood // WARNING: the values of IMAGES_MEDIA, AUDIO_MEDIA, and VIDEO_MEDIA and AUDIO_PLAYLISTS 499616dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood // are stored in the "files" table, so do not renumber them unless you also add 49971717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood // a corresponding database upgrade step for it. 4998702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int IMAGES_MEDIA = 1; 4999702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int IMAGES_MEDIA_ID = 2; 5000702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int IMAGES_THUMBNAILS = 3; 5001702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int IMAGES_THUMBNAILS_ID = 4; 5002702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 5003702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_MEDIA = 100; 5004702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_MEDIA_ID = 101; 5005702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_MEDIA_ID_GENRES = 102; 5006702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_MEDIA_ID_GENRES_ID = 103; 5007702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_MEDIA_ID_PLAYLISTS = 104; 5008702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_MEDIA_ID_PLAYLISTS_ID = 105; 5009702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_GENRES = 106; 5010702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_GENRES_ID = 107; 5011702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_GENRES_ID_MEMBERS = 108; 5012bfbc30ff3b9e3a96b08c525d0971d8d8543ab000Marco Nelissen private static final int AUDIO_GENRES_ALL_MEMBERS = 109; 5013702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_PLAYLISTS = 110; 5014702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_PLAYLISTS_ID = 111; 5015702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_PLAYLISTS_ID_MEMBERS = 112; 5016702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_PLAYLISTS_ID_MEMBERS_ID = 113; 5017702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ARTISTS = 114; 5018702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ARTISTS_ID = 115; 5019702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ALBUMS = 116; 5020702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ALBUMS_ID = 117; 5021702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ARTISTS_ID_ALBUMS = 118; 5022702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ALBUMART = 119; 5023702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ALBUMART_ID = 120; 502471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen private static final int AUDIO_ALBUMART_FILE_ID = 121; 5025702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 5026702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int VIDEO_MEDIA = 200; 5027702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int VIDEO_MEDIA_ID = 201; 5028b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private static final int VIDEO_THUMBNAILS = 202; 5029b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private static final int VIDEO_THUMBNAILS_ID = 203; 5030702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 5031702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int VOLUMES = 300; 5032702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int VOLUMES_ID = 301; 5033702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 5034a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen private static final int AUDIO_SEARCH_LEGACY = 400; 5035a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen private static final int AUDIO_SEARCH_BASIC = 401; 5036a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen private static final int AUDIO_SEARCH_FANCY = 402; 5037702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 5038702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int MEDIA_SCANNER = 500; 5039702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 50400027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen private static final int FS_ID = 600; 5041704a8b507b7aa61a09457075ed6f80c95914d731Marco Nelissen private static final int VERSION = 601; 50420027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen 504316dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood private static final int FILES = 700; 504416dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood private static final int FILES_ID = 701; 5045a36cfaef630ef5df7bef80b25f6bd493d040c7e4Brian Muramatsu 5046e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood // Used only by the MTP implementation 5047e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood private static final int MTP_OBJECTS = 702; 5048e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood private static final int MTP_OBJECTS_ID = 703; 5049e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood private static final int MTP_OBJECT_REFERENCES = 704; 5050819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood // UsbReceiver calls insert() and delete() with this URI to tell us 5051819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood // when MTP is connected and disconnected 5052819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood private static final int MTP_CONNECTED = 705; 5053b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 5054702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final UriMatcher URI_MATCHER = 5055702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project new UriMatcher(UriMatcher.NO_MATCH); 5056702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 5057b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private static final String[] ID_PROJECTION = new String[] { 5058b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen MediaStore.MediaColumns._ID 5059b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen }; 5060b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 50611d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood private static final String[] PATH_PROJECTION = new String[] { 50621d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood MediaStore.MediaColumns._ID, 50631d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood MediaStore.MediaColumns.DATA, 50641d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood }; 50651d4a47c46bd6476f624f2fa41f99d28c44a2ab0dMike Lockwood 5066702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final String[] MIME_TYPE_PROJECTION = new String[] { 5067702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.MediaColumns._ID, // 0 5068702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.MediaColumns.MIME_TYPE, // 1 5069702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project }; 5070702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 5071b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private static final String[] READY_FLAG_PROJECTION = new String[] { 5072b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen MediaStore.MediaColumns._ID, 5073b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen MediaStore.MediaColumns.DATA, 5074b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen Images.Media.MINI_THUMB_MAGIC 5075b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen }; 5076b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 5077e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood private static final String OBJECT_REFERENCES_QUERY = 5078afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood "SELECT " + Audio.Playlists.Members.AUDIO_ID + " FROM audio_playlists_map" 5079afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + " WHERE " + Audio.Playlists.Members.PLAYLIST_ID + "=?" 5080afa157c5799e410210af7d6b343cec8a9907afd2Mike Lockwood + " ORDER BY " + Audio.Playlists.Members.PLAY_ORDER; 5081e2eb1e85bbac2675c78c92cb1181b652ccd0b0f5Mike Lockwood 5082702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project static 5083702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project { 5084702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/images/media", IMAGES_MEDIA); 5085702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/images/media/#", IMAGES_MEDIA_ID); 5086702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/images/thumbnails", IMAGES_THUMBNAILS); 5087702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/images/thumbnails/#", IMAGES_THUMBNAILS_ID); 5088702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 5089702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/media", AUDIO_MEDIA); 5090702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/media/#", AUDIO_MEDIA_ID); 5091702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/media/#/genres", AUDIO_MEDIA_ID_GENRES); 5092702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/media/#/genres/#", AUDIO_MEDIA_ID_GENRES_ID); 5093702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/media/#/playlists", AUDIO_MEDIA_ID_PLAYLISTS); 5094702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/media/#/playlists/#", AUDIO_MEDIA_ID_PLAYLISTS_ID); 5095702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/genres", AUDIO_GENRES); 5096702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/genres/#", AUDIO_GENRES_ID); 5097702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/genres/#/members", AUDIO_GENRES_ID_MEMBERS); 5098bfbc30ff3b9e3a96b08c525d0971d8d8543ab000Marco Nelissen URI_MATCHER.addURI("media", "*/audio/genres/all/members", AUDIO_GENRES_ALL_MEMBERS); 5099702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/playlists", AUDIO_PLAYLISTS); 5100702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/playlists/#", AUDIO_PLAYLISTS_ID); 5101702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/playlists/#/members", AUDIO_PLAYLISTS_ID_MEMBERS); 5102702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/playlists/#/members/#", AUDIO_PLAYLISTS_ID_MEMBERS_ID); 5103702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/artists", AUDIO_ARTISTS); 5104702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/artists/#", AUDIO_ARTISTS_ID); 5105702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/artists/#/albums", AUDIO_ARTISTS_ID_ALBUMS); 5106702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/albums", AUDIO_ALBUMS); 5107702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/albums/#", AUDIO_ALBUMS_ID); 5108702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/albumart", AUDIO_ALBUMART); 5109702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/albumart/#", AUDIO_ALBUMART_ID); 511071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen URI_MATCHER.addURI("media", "*/audio/media/#/albumart", AUDIO_ALBUMART_FILE_ID); 5111702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 5112702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/video/media", VIDEO_MEDIA); 5113702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/video/media/#", VIDEO_MEDIA_ID); 5114b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen URI_MATCHER.addURI("media", "*/video/thumbnails", VIDEO_THUMBNAILS); 5115b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen URI_MATCHER.addURI("media", "*/video/thumbnails/#", VIDEO_THUMBNAILS_ID); 5116702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 5117702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/media_scanner", MEDIA_SCANNER); 5118702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 51190027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen URI_MATCHER.addURI("media", "*/fs_id", FS_ID); 5120704a8b507b7aa61a09457075ed6f80c95914d731Marco Nelissen URI_MATCHER.addURI("media", "*/version", VERSION); 51210027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen 5122819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood URI_MATCHER.addURI("media", "*/mtp_connected", MTP_CONNECTED); 5123819cafdb3d4c3ce8a74d3b572b8ca0a0b639e8b2Mike Lockwood 5124702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*", VOLUMES_ID); 5125702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", null, VOLUMES); 5126702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 5127b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood // Used by MTP implementation 512816dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood URI_MATCHER.addURI("media", "*/file", FILES); 512916dc0fdb9a80e09adb68864a7888c2ab6f3dc7afMike Lockwood URI_MATCHER.addURI("media", "*/file/#", FILES_ID); 5130e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood URI_MATCHER.addURI("media", "*/object", MTP_OBJECTS); 5131e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood URI_MATCHER.addURI("media", "*/object/#", MTP_OBJECTS_ID); 5132e2c981f26abf2b46d0ff2175dc996fd680073b7bMike Lockwood URI_MATCHER.addURI("media", "*/object/#/references", MTP_OBJECT_REFERENCES); 5133b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 5134a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen /** 5135a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen * @deprecated use the 'basic' or 'fancy' search Uris instead 5136a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen */ 5137702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/" + SearchManager.SUGGEST_URI_PATH_QUERY, 5138a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen AUDIO_SEARCH_LEGACY); 5139702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/" + SearchManager.SUGGEST_URI_PATH_QUERY + "/*", 5140a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen AUDIO_SEARCH_LEGACY); 5141a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen 5142a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // used for search suggestions 5143a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen URI_MATCHER.addURI("media", "*/audio/search/" + SearchManager.SUGGEST_URI_PATH_QUERY, 5144a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen AUDIO_SEARCH_BASIC); 5145a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen URI_MATCHER.addURI("media", "*/audio/search/" + SearchManager.SUGGEST_URI_PATH_QUERY + 5146a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "/*", AUDIO_SEARCH_BASIC); 5147a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen 5148a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // used by the music app's search activity 5149a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen URI_MATCHER.addURI("media", "*/audio/search/fancy", AUDIO_SEARCH_FANCY); 5150a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen URI_MATCHER.addURI("media", "*/audio/search/fancy/*", AUDIO_SEARCH_FANCY); 5151702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 515210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen 515310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen @Override 515410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { 515510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen Collection<DatabaseHelper> foo = mDatabases.values(); 515610af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen for (DatabaseHelper dbh: foo) { 5157988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen writer.println(dump(dbh, true)); 5158988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen } 5159988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen writer.flush(); 5160988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen } 5161988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen 5162988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen private String dump(DatabaseHelper dbh, boolean dumpDbLog) { 5163988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen StringBuilder s = new StringBuilder(); 5164988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen s.append(dbh.mName); 5165988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen s.append(": "); 5166988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen SQLiteDatabase db = dbh.getReadableDatabase(); 5167988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen if (db == null) { 5168988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen s.append("null"); 5169988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen } else { 5170988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen s.append("version " + db.getVersion() + ", "); 5171988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen Cursor c = db.query("files", new String[] {"count(*)"}, null, null, null, null, null); 5172988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen try { 5173988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen if (c != null && c.moveToFirst()) { 5174988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen int num = c.getInt(0); 5175988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen s.append(num + " rows, "); 5176988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen } else { 5177988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen s.append("couldn't get row count, "); 5178988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen } 5179988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen } finally { 5180988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen if (c != null) { 5181988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen c.close(); 5182988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen } 5183988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen } 5184988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen s.append(dbh.mNumInserts + " inserts, "); 5185988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen s.append(dbh.mNumUpdates + " updates, "); 5186988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen s.append(dbh.mNumDeletes + " deletes, "); 5187988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen s.append(dbh.mNumQueries + " queries, "); 5188988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen if (dbh.mScanStartTime != 0) { 5189988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen s.append("scan started " + DateUtils.formatDateTime(getContext(), 5190988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen dbh.mScanStartTime / 1000, 5191988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen DateUtils.FORMAT_SHOW_DATE 5192988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen | DateUtils.FORMAT_SHOW_TIME 5193988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen | DateUtils.FORMAT_ABBREV_ALL)); 5194988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen long now = dbh.mScanStopTime; 5195988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen if (now < dbh.mScanStartTime) { 5196988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen now = SystemClock.currentTimeMicro(); 5197988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen } 5198988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen s.append(" (" + DateUtils.formatElapsedTime( 5199988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen (now - dbh.mScanStartTime) / 1000000) + ")"); 5200988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen if (dbh.mScanStopTime < dbh.mScanStartTime) { 5201988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen if (mMediaScannerVolume != null && 5202988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen dbh.mName.startsWith(mMediaScannerVolume)) { 5203988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen s.append(" (ongoing)"); 520410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen } else { 5205988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen s.append(" (scanning " + mMediaScannerVolume + ")"); 5206988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen } 5207988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen } 5208988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen } 5209988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen if (dumpDbLog) { 5210988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen c = db.query("log", new String[] {"time", "message"}, 5211988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen null, null, null, null, "time"); 5212988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen try { 5213988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen if (c != null) { 5214988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen while (c.moveToNext()) { 5215988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen String when = c.getString(0); 5216988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen String msg = c.getString(1); 5217988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen s.append("\n" + when + " : " + msg); 5218988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen } 521910af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen } 522010af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen } finally { 522110af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen if (c != null) { 522210af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen c.close(); 522310af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen } 522410af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen } 522510af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen } 522610af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen } 5227988280a7b7cba5888b943a6db05aab703fd9c35aMarco Nelissen return s.toString(); 522810af34f31704509a71d02b0b4a15cfa07bbfede3Marco Nelissen } 5229702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project} 5230