MediaProvider.java revision 4d96d72ea42c2ec41a891f65623270473ae8eebd
1702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project/* 2702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Copyright (C) 2006 The Android Open Source Project 3702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 4702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 5702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * you may not use this file except in compliance with the License. 6702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * You may obtain a copy of the License at 7702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 8702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 9702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 10702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software 11702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 12702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * See the License for the specific language governing permissions and 14702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * limitations under the License. 15702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 16702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 17702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectpackage com.android.providers.media; 18702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 19702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.app.SearchManager; 20702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.content.*; 21702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.database.Cursor; 22702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.database.SQLException; 23702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.database.sqlite.SQLiteDatabase; 24702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.database.sqlite.SQLiteOpenHelper; 25702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.database.sqlite.SQLiteQueryBuilder; 26702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.graphics.Bitmap; 27702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.graphics.BitmapFactory; 28702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.media.MediaFile; 29702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.media.MediaScanner; 30b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chenimport android.media.MiniThumbFile; 31702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.net.Uri; 32702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.Binder; 33702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.Environment; 34702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.FileUtils; 35702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.Handler; 36702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.Looper; 3771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissenimport android.os.MemoryFile; 38702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.Message; 39702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.ParcelFileDescriptor; 40702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.Process; 41702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.BaseColumns; 42702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.MediaStore; 43702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.MediaStore.Audio; 44702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.MediaStore.Images; 45702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.MediaStore.MediaColumns; 46702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.MediaStore.Video; 47702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.MediaStore.Images.ImageColumns; 48702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.text.TextUtils; 49702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.util.Log; 50702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 51702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.io.File; 52702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.io.FileInputStream; 53702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.io.FileNotFoundException; 54702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.io.IOException; 55702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.io.OutputStream; 56702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.text.Collator; 57702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.util.HashMap; 58702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.util.HashSet; 59702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.util.Iterator; 60b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chenimport java.util.PriorityQueue; 618a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huberimport java.util.Stack; 62702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 63702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project/** 64702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Media content provider. See {@link android.provider.MediaStore} for details. 65702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Separate databases are kept for each external storage card we see (using the 66702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * card's ID as an index). The content visible at content://media/external/... 67702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * changes with the card. 68702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 69702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectpublic class MediaProvider extends ContentProvider { 70702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final Uri MEDIA_URI = Uri.parse("content://media"); 71702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final Uri ALBUMART_URI = Uri.parse("content://media/external/audio/albumart"); 72b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private static final int ALBUM_THUMB = 1; 73b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private static final int IMAGE_THUMB = 2; 74702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 75702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final HashMap<String, String> sArtistAlbumsMap = new HashMap<String, String>(); 76d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen private static final HashMap<String, String> sFolderArtMap = new HashMap<String, String>(); 77702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 788a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // A HashSet of paths that are pending creation of album art thumbnails. 798a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber private HashSet mPendingThumbs = new HashSet(); 808a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 818a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // A Stack of outstanding thumbnail requests. 828a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber private Stack mThumbRequestStack = new Stack(); 838a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 84b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private PriorityQueue<MediaThumbRequest> mMediaThumbQueue = 85b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen new PriorityQueue<MediaThumbRequest>(MediaThumbRequest.PRIORITY_NORMAL, 86b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen MediaThumbRequest.getComparator()); 87b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 88a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // For compatibility with the approximately 0 apps that used mediaprovider search in 89a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // releases 1.0, 1.1 or 1.5 90a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen private String[] mSearchColsLegacy = new String[] { 91a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen android.provider.BaseColumns._ID, 92a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen MediaStore.Audio.Media.MIME_TYPE, 93a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "(CASE WHEN grouporder=1 THEN " + R.drawable.ic_search_category_music_artist + 94a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen " ELSE CASE WHEN grouporder=2 THEN " + R.drawable.ic_search_category_music_album + 95a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen " ELSE " + R.drawable.ic_search_category_music_song + " END END" + 96a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen ") AS " + SearchManager.SUGGEST_COLUMN_ICON_1, 97a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "0 AS " + SearchManager.SUGGEST_COLUMN_ICON_2, 98a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "text1 AS " + SearchManager.SUGGEST_COLUMN_TEXT_1, 99a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "text1 AS " + SearchManager.SUGGEST_COLUMN_QUERY, 100a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "CASE when grouporder=1 THEN data1 ELSE artist END AS data1", 101a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "CASE when grouporder=1 THEN data2 ELSE " + 102a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "CASE WHEN grouporder=2 THEN NULL ELSE album END END AS data2", 103a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "match as ar", 104a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen SearchManager.SUGGEST_COLUMN_INTENT_DATA, 105a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "grouporder", 106ea74c8add2d5b4215dfeb69183632d9e9797ac5aMarco Nelissen "NULL AS itemorder" // We should be sorting by the artist/album/title keys, but that 107ea74c8add2d5b4215dfeb69183632d9e9797ac5aMarco Nelissen // column is not available here, and the list is already sorted. 108a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen }; 109a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen private String[] mSearchColsFancy = new String[] { 110a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen android.provider.BaseColumns._ID, 111a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen MediaStore.Audio.Media.MIME_TYPE, 112a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen MediaStore.Audio.Artists.ARTIST, 113a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen MediaStore.Audio.Albums.ALBUM, 114a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen MediaStore.Audio.Media.TITLE, 115a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "data1", 116a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "data2", 117a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen }; 11863f748ff8b258d9110038778a006b3000164fbeeSatish Sampath // If this array gets changed, please update the constant below to point to the correct item. 119a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen private String[] mSearchColsBasic = new String[] { 120a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen android.provider.BaseColumns._ID, 121a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen MediaStore.Audio.Media.MIME_TYPE, 122a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "(CASE WHEN grouporder=1 THEN " + R.drawable.ic_search_category_music_artist + 123a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen " ELSE CASE WHEN grouporder=2 THEN " + R.drawable.ic_search_category_music_album + 124a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen " ELSE " + R.drawable.ic_search_category_music_song + " END END" + 125a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen ") AS " + SearchManager.SUGGEST_COLUMN_ICON_1, 126a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "text1 AS " + SearchManager.SUGGEST_COLUMN_TEXT_1, 127a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "text1 AS " + SearchManager.SUGGEST_COLUMN_QUERY, 12863f748ff8b258d9110038778a006b3000164fbeeSatish Sampath "(CASE WHEN grouporder=1 THEN '%1'" + // %1 gets replaced with localized string. 12963f748ff8b258d9110038778a006b3000164fbeeSatish Sampath " ELSE CASE WHEN grouporder=3 THEN artist || ' - ' || album" + 13063f748ff8b258d9110038778a006b3000164fbeeSatish Sampath " ELSE CASE WHEN text2!='" + MediaFile.UNKNOWN_STRING + "' THEN text2" + 13163f748ff8b258d9110038778a006b3000164fbeeSatish Sampath " ELSE NULL END END END) AS " + SearchManager.SUGGEST_COLUMN_TEXT_2, 132a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen SearchManager.SUGGEST_COLUMN_INTENT_DATA 133a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen }; 13463f748ff8b258d9110038778a006b3000164fbeeSatish Sampath // Position of the TEXT_2 item in the above array. 13563f748ff8b258d9110038778a006b3000164fbeeSatish Sampath private final int SEARCH_COLUMN_BASIC_TEXT2 = 5; 136a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen 137a9c4e330dacb37cfffa9c00f7da83cafde4accefMarco Nelissen private Uri mAlbumArtBaseUri = Uri.parse("content://media/external/audio/albumart"); 138a9c4e330dacb37cfffa9c00f7da83cafde4accefMarco Nelissen 139702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private BroadcastReceiver mUnmountReceiver = new BroadcastReceiver() { 140702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 141702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public void onReceive(Context context, Intent intent) { 142702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (intent.getAction().equals(Intent.ACTION_MEDIA_EJECT)) { 143702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Remove the external volume and then notify all cursors backed by 144702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // data on that volume 145702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project detachVolume(Uri.parse("content://media/external")); 146d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen sFolderArtMap.clear(); 147b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen MiniThumbFile.reset(); 148702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 149702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 150702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project }; 151702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 152702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 153702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Wrapper class for a specific database (associated with one particular 154702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * external card, or with internal storage). Can open the actual database 155702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * on demand, create and upgrade the schema, etc. 156702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 157702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final class DatabaseHelper extends SQLiteOpenHelper { 158702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final Context mContext; 159702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final boolean mInternal; // True if this is the internal database 160702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 161702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // In memory caches of artist and album data. 162702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project HashMap<String, Long> mArtistCache = new HashMap<String, Long>(); 163702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project HashMap<String, Long> mAlbumCache = new HashMap<String, Long>(); 164702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 165702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public DatabaseHelper(Context context, String name, boolean internal) { 166702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project super(context, name, null, DATABASE_VERSION); 167702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mContext = context; 168702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mInternal = internal; 169702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 170702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 171702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 172702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Creates database the first time we try to open it. 173702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 174702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 175702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public void onCreate(final SQLiteDatabase db) { 176702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project updateDatabase(db, mInternal, 0, DATABASE_VERSION); 177702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 178702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 179702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 180702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Updates the database format when a new content provider is used 181702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * with an older database format. 182702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 183702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 184702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public void onUpgrade(final SQLiteDatabase db, final int oldV, final int newV) { 185702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project updateDatabase(db, mInternal, oldV, newV); 186702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 187702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 188702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 189702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Touch this particular database and garbage collect old databases. 190702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * An LRU cache system is used to clean up databases for old external 191702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * storage volumes. 192702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 193702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 194702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public void onOpen(SQLiteDatabase db) { 195702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (mInternal) return; // The internal database is kept separately. 196702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 197702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // touch the database file to show it is most recently used 198702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File file = new File(db.getPath()); 199702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long now = System.currentTimeMillis(); 200702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project file.setLastModified(now); 201702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 202702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // delete least recently used databases if we are over the limit 203702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String[] databases = mContext.databaseList(); 204702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int count = databases.length; 205702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int limit = MAX_EXTERNAL_DATABASES; 206702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 207702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // delete external databases that have not been used in the past two months 208702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long twoMonthsAgo = now - OBSOLETE_DATABASE_DB; 209702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project for (int i = 0; i < databases.length; i++) { 210702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File other = mContext.getDatabasePath(databases[i]); 211702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (INTERNAL_DATABASE_NAME.equals(databases[i]) || file.equals(other)) { 212702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project databases[i] = null; 213702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count--; 214702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (file.equals(other)) { 215702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // reduce limit to account for the existence of the database we 216702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // are about to open, which we removed from the list. 217702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project limit--; 218702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 219702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 220702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long time = other.lastModified(); 221702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (time < twoMonthsAgo) { 222702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (LOCAL_LOGV) Log.v(TAG, "Deleting old database " + databases[i]); 223702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mContext.deleteDatabase(databases[i]); 224702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project databases[i] = null; 225702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count--; 226702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 227702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 228702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 229702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 230702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // delete least recently used databases until 231702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // we are no longer over the limit 232702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project while (count > limit) { 233702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int lruIndex = -1; 234702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long lruTime = 0; 235702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 236702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project for (int i = 0; i < databases.length; i++) { 237702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (databases[i] != null) { 238702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long time = mContext.getDatabasePath(databases[i]).lastModified(); 239702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (lruTime == 0 || time < lruTime) { 240702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project lruIndex = i; 241702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project lruTime = time; 242702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 243702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 244702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 245702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 246702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // delete least recently used database 247702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (lruIndex != -1) { 248702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (LOCAL_LOGV) Log.v(TAG, "Deleting old database " + databases[lruIndex]); 249702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mContext.deleteDatabase(databases[lruIndex]); 250702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project databases[lruIndex] = null; 251702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count--; 252702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 253702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 254702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 255702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 256702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 257702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 258702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public boolean onCreate() { 259702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Albums._ID, "audio.album_id AS " + 260702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.Audio.Albums._ID); 261702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Albums.ALBUM, "album"); 262702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Albums.ALBUM_KEY, "album_key"); 263702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Albums.FIRST_YEAR, "MIN(year) AS " + 264702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.Audio.Albums.FIRST_YEAR); 265702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Albums.LAST_YEAR, "MAX(year) AS " + 266702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.Audio.Albums.LAST_YEAR); 267702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Media.ARTIST, "artist"); 268702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Media.ARTIST_ID, "artist"); 269702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Media.ARTIST_KEY, "artist_key"); 270702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Albums.NUMBER_OF_SONGS, "count(*) AS " + 271702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.Audio.Albums.NUMBER_OF_SONGS); 272702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Albums.ALBUM_ART, "album_art._data AS " + 273702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.Audio.Albums.ALBUM_ART); 274702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 27563f748ff8b258d9110038778a006b3000164fbeeSatish Sampath mSearchColsBasic[SEARCH_COLUMN_BASIC_TEXT2] = 27663f748ff8b258d9110038778a006b3000164fbeeSatish Sampath mSearchColsBasic[SEARCH_COLUMN_BASIC_TEXT2].replaceAll( 27763f748ff8b258d9110038778a006b3000164fbeeSatish Sampath "%1", getContext().getString(R.string.artist_label)); 278702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mDatabases = new HashMap<String, DatabaseHelper>(); 279702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project attachVolume(INTERNAL_VOLUME); 280702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 281702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project IntentFilter iFilter = new IntentFilter(Intent.ACTION_MEDIA_EJECT); 282702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project iFilter.addDataScheme("file"); 283702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().registerReceiver(mUnmountReceiver, iFilter); 284702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 285702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // open external database if external storage is mounted 286702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String state = Environment.getExternalStorageState(); 287702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (Environment.MEDIA_MOUNTED.equals(state) || 288702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) { 289702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project attachVolume(EXTERNAL_VOLUME); 290702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 291702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 292b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen mThumbWorker = new Worker("thumbs thread"); 293702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mThumbHandler = new Handler(mThumbWorker.getLooper()) { 294702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 295702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public void handleMessage(Message msg) { 296b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (msg.what == IMAGE_THUMB) { 297b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen MediaThumbRequest req; 298b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen synchronized (mMediaThumbQueue) { 299b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen req = mMediaThumbQueue.poll(); 300b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 301b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (req == null) { 302b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen Log.w(TAG, "Have message but no request?"); 303b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } else { 304b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // Log.v(TAG, "we got work to do for checkThumbnail: "+ req.mPath ); 305b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen try { 3064d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen File origFile = new File(req.mPath); 3074d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen if (origFile.exists() && origFile.length() > 0) { 3084d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen req.execute(); 3094d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen } else { 3104d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen // original file hasn't been stored yet 3114d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen synchronized (mMediaThumbQueue) { 3124d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen Log.w(TAG, "original file hasn't been stored yet: " + req.mPath); 3134d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen } 3144d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen } 315b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } catch (IOException ex) { 316b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen Log.e(TAG, "", ex); 317b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } finally { 318b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen req.mDone = true; 319b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen synchronized (req) { 320b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen req.notifyAll(); 321b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 322b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 323b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 324b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } else if (msg.what == ALBUM_THUMB) { 325b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen ThumbData d; 326b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen synchronized (mThumbRequestStack) { 327b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen d = (ThumbData)mThumbRequestStack.pop(); 328b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 3298a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 330b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen makeThumbInternal(d); 331b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen synchronized (mPendingThumbs) { 332b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen mPendingThumbs.remove(d.path); 333b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 3348a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 335702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 336702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project }; 337702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 338702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return true; 339702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 340702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 341702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 342702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * This method takes care of updating all the tables in the database to the 343702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * current version, creating them if necessary. 344702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * This method can only update databases at schema 63 or higher, which was 345702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * created August 1, 2008. Older database will be cleared and recreated. 346702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param db Database 347702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param internal True if this is the internal media database 348702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 349702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static void updateDatabase(SQLiteDatabase db, boolean internal, 350702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int fromVersion, int toVersion) { 351702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 352702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // sanity checks 353702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (toVersion != DATABASE_VERSION) { 354702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Log.e(TAG, "Illegal update request. Got " + toVersion + ", expected " + 355702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DATABASE_VERSION); 356702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalArgumentException(); 357702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else if (fromVersion > toVersion) { 35895ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen Log.e(TAG, "Illegal update request: can't downgrade from " + fromVersion + 359702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " to " + toVersion + ". Did you forget to wipe data?"); 360702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalArgumentException(); 361702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 362702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 363702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 63) { 364702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Drop everything and start over. 365702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Log.i(TAG, "Upgrading media database from version " + 366702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project fromVersion + " to " + toVersion + ", which will destroy all old data"); 367702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS images"); 368702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS images_cleanup"); 369702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS thumbnails"); 370702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS thumbnails_cleanup"); 371702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS audio_meta"); 372702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS artists"); 373702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS albums"); 374702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS album_art"); 375702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP VIEW IF EXISTS artist_info"); 376702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP VIEW IF EXISTS album_info"); 377702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP VIEW IF EXISTS artists_albums_map"); 378702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS audio_meta_cleanup"); 379702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS audio_genres"); 380702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS audio_genres_map"); 381702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS audio_genres_cleanup"); 382702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS audio_playlists"); 383702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS audio_playlists_map"); 384702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS audio_playlists_cleanup"); 385702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS albumart_cleanup1"); 386702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS albumart_cleanup2"); 387702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS video"); 388702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS video_cleanup"); 389702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 390702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS images (" + 391702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 392702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_data TEXT," + 393702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_size INTEGER," + 394702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_display_name TEXT," + 395702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "mime_type TEXT," + 396702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "title TEXT," + 397702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_added INTEGER," + 398702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_modified INTEGER," + 399702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "description TEXT," + 400702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "picasa_id TEXT," + 401702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "isprivate INTEGER," + 402702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "latitude DOUBLE," + 403702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "longitude DOUBLE," + 404702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "datetaken INTEGER," + 405702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "orientation INTEGER," + 406702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "mini_thumb_magic INTEGER," + 407702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "bucket_id TEXT," + 408702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "bucket_display_name TEXT" + 409702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 410702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 411702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE INDEX IF NOT EXISTS mini_thumb_magic_index on images(mini_thumb_magic);"); 412702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 413702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS images_cleanup DELETE ON images " + 414702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 415702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE FROM thumbnails WHERE image_id = old._id;" + 416702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT _DELETE_FILE(old._data);" + 417702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 418702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 419b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // create image thumbnail table 420702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS thumbnails (" + 421702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 422702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_data TEXT," + 423702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "image_id INTEGER," + 424702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "kind INTEGER," + 425702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "width INTEGER," + 426702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "height INTEGER" + 427702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 428702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 429702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE INDEX IF NOT EXISTS image_id_index on thumbnails(image_id);"); 430702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 431702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS thumbnails_cleanup DELETE ON thumbnails " + 432702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 433702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT _DELETE_FILE(old._data);" + 434702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 435702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 436702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains meta data about audio files 437702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS audio_meta (" + 438702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 439702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_data TEXT NOT NULL," + 440702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_display_name TEXT," + 441702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_size INTEGER," + 442702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "mime_type TEXT," + 443702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_added INTEGER," + 444702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_modified INTEGER," + 445702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "title TEXT NOT NULL," + 446702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "title_key TEXT NOT NULL," + 447702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "duration INTEGER," + 448702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "artist_id INTEGER," + 449702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "composer TEXT," + 450702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "album_id INTEGER," + 451702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "track INTEGER," + // track is an integer to allow proper sorting 452702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "year INTEGER CHECK(year!=0)," + 453702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "is_ringtone INTEGER," + 454702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "is_music INTEGER," + 455702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "is_alarm INTEGER," + 456702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "is_notification INTEGER" + 457702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 458702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 459702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains a sort/group "key" and the preferred display name for artists 460702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS artists (" + 461702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "artist_id INTEGER PRIMARY KEY," + 462702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "artist_key TEXT NOT NULL UNIQUE," + 463702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "artist TEXT NOT NULL" + 464702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 465702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 466702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains a sort/group "key" and the preferred display name for albums 467702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS albums (" + 468702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "album_id INTEGER PRIMARY KEY," + 469702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "album_key TEXT NOT NULL UNIQUE," + 470702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "album TEXT NOT NULL" + 471702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 472702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 473702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS album_art (" + 474702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "album_id INTEGER PRIMARY KEY," + 475702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_data TEXT" + 476702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 477702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 478702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project recreateAudioView(db); 47995ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen 480702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 481702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Provides some extra info about artists, like the number of tracks 482702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // and albums for this artist 483702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE VIEW IF NOT EXISTS artist_info AS " + 484702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT artist_id AS _id, artist, artist_key, " + 485702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "COUNT(DISTINCT album) AS number_of_albums, " + 486702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "COUNT(*) AS number_of_tracks FROM audio WHERE is_music=1 "+ 487702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "GROUP BY artist_key;"); 488702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 489702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Provides extra info albums, such as the number of tracks 490702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE VIEW IF NOT EXISTS album_info AS " + 491702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT audio.album_id AS _id, album, album_key, " + 492702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "MIN(year) AS minyear, " + 493702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "MAX(year) AS maxyear, artist, artist_id, artist_key, " + 494702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "count(*) AS " + MediaStore.Audio.Albums.NUMBER_OF_SONGS + 495702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ",album_art._data AS album_art" + 496702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " FROM audio LEFT OUTER JOIN album_art ON audio.album_id=album_art.album_id" + 497702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " WHERE is_music=1 GROUP BY audio.album_id;"); 498702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 499702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // For a given artist_id, provides the album_id for albums on 500702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // which the artist appears. 501702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE VIEW IF NOT EXISTS artists_albums_map AS " + 502702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT DISTINCT artist_id, album_id FROM audio_meta;"); 503702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 504702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /* 505702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Only external media volumes can handle genres, playlists, etc. 506702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 507702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!internal) { 508702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Cleans up when an audio file is deleted 509702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS audio_meta_cleanup DELETE ON audio_meta " + 510702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 511702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE FROM audio_genres_map WHERE audio_id = old._id;" + 512702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE FROM audio_playlists_map WHERE audio_id = old._id;" + 513702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 514702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 515702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains audio genre definitions 516702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS audio_genres (" + 517702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 518702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "name TEXT NOT NULL" + 519702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 520702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 521702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contiains mappings between audio genres and audio files 522702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS audio_genres_map (" + 523702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 524702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_id INTEGER NOT NULL," + 525702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "genre_id INTEGER NOT NULL" + 526702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 527702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 528702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Cleans up when an audio genre is delete 529702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS audio_genres_cleanup DELETE ON audio_genres " + 530702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 531702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE FROM audio_genres_map WHERE genre_id = old._id;" + 532702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 533702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 534702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains audio playlist definitions 535702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS audio_playlists (" + 536702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 537702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_data TEXT," + // _data is path for file based playlists, or null 538702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "name TEXT NOT NULL," + 539702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_added INTEGER," + 540702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_modified INTEGER" + 541702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 542702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 543702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains mappings between audio playlists and audio files 544702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS audio_playlists_map (" + 545702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 546702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_id INTEGER NOT NULL," + 547702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "playlist_id INTEGER NOT NULL," + 548702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "play_order INTEGER NOT NULL" + 549702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 550702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 551702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Cleans up when an audio playlist is deleted 552702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS audio_playlists_cleanup DELETE ON audio_playlists " + 553702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 554702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE FROM audio_playlists_map WHERE playlist_id = old._id;" + 555702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT _DELETE_FILE(old._data);" + 556702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 557702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 558702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Cleans up album_art table entry when an album is deleted 559702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS albumart_cleanup1 DELETE ON albums " + 560702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 561702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE FROM album_art WHERE album_id = old.album_id;" + 562702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 563702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 564702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Cleans up album_art when an album is deleted 565702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS albumart_cleanup2 DELETE ON album_art " + 566702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 567702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT _DELETE_FILE(old._data);" + 568702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 569702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 570702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 571702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains meta data about video files 572702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS video (" + 573702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 574702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_data TEXT NOT NULL," + 575702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_display_name TEXT," + 576702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_size INTEGER," + 577702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "mime_type TEXT," + 578702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_added INTEGER," + 579702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_modified INTEGER," + 580702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "title TEXT," + 581702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "duration INTEGER," + 582702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "artist TEXT," + 583702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "album TEXT," + 584702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "resolution TEXT," + 585702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "description TEXT," + 586702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "isprivate INTEGER," + // for YouTube videos 587702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "tags TEXT," + // for YouTube videos 588702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "category TEXT," + // for YouTube videos 589702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "language TEXT," + // for YouTube videos 590702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "mini_thumb_data TEXT," + 591702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "latitude DOUBLE," + 592702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "longitude DOUBLE," + 593702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "datetaken INTEGER," + 594702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "mini_thumb_magic INTEGER" + 595702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 596702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 597702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS video_cleanup DELETE ON video " + 598702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 599702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT _DELETE_FILE(old._data);" + 600702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 601702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 602702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 603702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // At this point the database is at least at schema version 63 (it was 604702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // either created at version 63 by the code above, or was already at 605702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // version 63 or later) 606702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 607702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 64) { 608702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // create the index that updates the database to schema version 64 609702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE INDEX IF NOT EXISTS sort_index on images(datetaken ASC, _id ASC);"); 610702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 611702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 612702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 65) { 613702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // create the index that updates the database to schema version 65 614702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE INDEX IF NOT EXISTS titlekey_index on audio_meta(title_key);"); 615702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 616702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 617702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 66) { 618702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project updateBucketNames(db, "images"); 619702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 620702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 621702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 67) { 622702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // create the indices that update the database to schema version 67 623702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE INDEX IF NOT EXISTS albumkey_index on albums(album_key);"); 624702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE INDEX IF NOT EXISTS artistkey_index on artists(artist_key);"); 625702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 626702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 627702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 68) { 628702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Create bucket_id and bucket_display_name columns for the video table. 629702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("ALTER TABLE video ADD COLUMN bucket_id TEXT;"); 630702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("ALTER TABLE video ADD COLUMN bucket_display_name TEXT"); 631702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project updateBucketNames(db, "video"); 632702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 633702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 634702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 69) { 635702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project updateDisplayName(db, "images"); 636702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 637702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 638702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 70) { 639702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Create bookmark column for the video table. 640702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("ALTER TABLE video ADD COLUMN bookmark INTEGER;"); 641702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 64295ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen 643702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 71) { 644702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // There is no change to the database schema, however a code change 645702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // fixed parsing of metadata for certain files bought from the 646702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // iTunes music store, so we want to rescan files that might need it. 647702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // We do this by clearing the modification date in the database for 648702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // those files, so that the media scanner will see them as updated 649702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // and rescan them. 650702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("UPDATE audio_meta SET date_modified=0 WHERE _id IN (" + 651702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT _id FROM audio where mime_type='audio/mp4' AND " + 652702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "artist='" + MediaFile.UNKNOWN_STRING + "' AND " + 653702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "album='" + MediaFile.UNKNOWN_STRING + "'" + 654702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 655702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 65695ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen 657702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 72) { 658702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Create is_podcast and bookmark columns for the audio table. 659702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("ALTER TABLE audio_meta ADD COLUMN is_podcast INTEGER;"); 660702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("UPDATE audio_meta SET is_podcast=1 WHERE _data LIKE '%/podcasts/%';"); 661702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("UPDATE audio_meta SET is_music=0 WHERE is_podcast=1" + 662702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " AND _data NOT LIKE '%/music/%';"); 663702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("ALTER TABLE audio_meta ADD COLUMN bookmark INTEGER;"); 664702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 665702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // New columns added to tables aren't visible in views on those tables 666702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // without opening and closing the database (or using the 'vacuum' command, 667702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // which we can't do here because all this code runs inside a transaction). 668702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // To work around this, we drop and recreate the affected view and trigger. 669702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project recreateAudioView(db); 670702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 67195ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen 6728d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen if (fromVersion < 73) { 6738d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen // There is no change to the database schema, but we now do case insensitive 6748d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen // matching of folder names when determining whether something is music, a 6758d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen // ringtone, podcast, etc, so we might need to reclassify some files. 6768d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen db.execSQL("UPDATE audio_meta SET is_music=1 WHERE is_music=0 AND " + 6778d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen "_data LIKE '%/music/%';"); 6788d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen db.execSQL("UPDATE audio_meta SET is_ringtone=1 WHERE is_ringtone=0 AND " + 6798d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen "_data LIKE '%/ringtones/%';"); 6808d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen db.execSQL("UPDATE audio_meta SET is_notification=1 WHERE is_notification=0 AND " + 6818d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen "_data LIKE '%/notifications/%';"); 6828d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen db.execSQL("UPDATE audio_meta SET is_alarm=1 WHERE is_alarm=0 AND " + 6838d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen "_data LIKE '%/alarms/%';"); 6848d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen db.execSQL("UPDATE audio_meta SET is_podcast=1 WHERE is_podcast=0 AND " + 6858d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen "_data LIKE '%/podcasts/%';"); 6868d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen } 687a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen 688a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen if (fromVersion < 74) { 689a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // This view is used instead of the audio view by the union below, to force 690a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // sqlite to use the title_key index. This greatly reduces memory usage 691a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // (no separate copy pass needed for sorting, which could cause errors on 692a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // large datasets) and improves speed (by about 35% on a large dataset) 693a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen db.execSQL("CREATE VIEW IF NOT EXISTS searchhelpertitle AS SELECT * FROM audio " + 694a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "ORDER BY title_key;"); 695a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen 696a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen db.execSQL("CREATE VIEW IF NOT EXISTS search AS " + 697a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "SELECT _id," + 698a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "'artist' AS mime_type," + 699a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist," + 700a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS album," + 701a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS title," + 702a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist AS text1," + 703a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS text2," + 704a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "number_of_albums AS data1," + 705a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "number_of_tracks AS data2," + 706a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist_key AS match," + 707a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "'content://media/external/audio/artists/'||_id AS suggest_intent_data," + 708a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "1 AS grouporder " + 709a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "FROM artist_info WHERE (artist!='" + MediaFile.UNKNOWN_STRING + "') " + 710a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "UNION ALL " + 711a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "SELECT _id," + 712a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "'album' AS mime_type," + 713a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist," + 714a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "album," + 715a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS title," + 716a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "album AS text1," + 717a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist AS text2," + 718a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS data1," + 719a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS data2," + 720a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist_key||' '||album_key AS match," + 721a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "'content://media/external/audio/albums/'||_id AS suggest_intent_data," + 722a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "2 AS grouporder " + 723a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "FROM album_info WHERE (album!='" + MediaFile.UNKNOWN_STRING + "') " + 724a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "UNION ALL " + 725a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "SELECT searchhelpertitle._id AS _id," + 726a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "mime_type," + 727a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist," + 728a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "album," + 729a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "title," + 730a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "title AS text1," + 731a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist AS text2," + 732a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS data1," + 733a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS data2," + 734a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist_key||' '||album_key||' '||title_key AS match," + 735a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "'content://media/external/audio/media/'||searchhelpertitle._id AS " + 736a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "suggest_intent_data," + 737a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "3 AS grouporder " + 738a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "FROM searchhelpertitle WHERE (title != '') " 739a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen ); 740a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen } 74159948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen 74259948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen if (fromVersion < 75) { 74395ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen // Force a rescan of the audio entries so we can apply the new logic to 74459948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // distinguish same-named albums. 74559948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen db.execSQL("UPDATE audio_meta SET date_modified=0;"); 74659948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen db.execSQL("DELETE FROM albums"); 74759948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen } 74815d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen 74915d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen if (fromVersion < 76) { 75015d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen // We now ignore double quotes when building the key, so we have to remove all of them 75115d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen // from existing keys. 75215d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen db.execSQL("UPDATE audio_meta SET title_key=" + 75315d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen "REPLACE(title_key,x'081D08C29F081D',x'081D') " + 75415d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen "WHERE title_key LIKE '%'||x'081D08C29F081D'||'%';"); 75515d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen db.execSQL("UPDATE albums SET album_key=" + 75615d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen "REPLACE(album_key,x'081D08C29F081D',x'081D') " + 75715d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen "WHERE album_key LIKE '%'||x'081D08C29F081D'||'%';"); 75815d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen db.execSQL("UPDATE artists SET artist_key=" + 75915d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen "REPLACE(artist_key,x'081D08C29F081D',x'081D') " + 76015d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen "WHERE artist_key LIKE '%'||x'081D08C29F081D'||'%';"); 76115d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen } 762b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 763b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (fromVersion < 77) { 764b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // create video thumbnail table 765b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen db.execSQL("CREATE TABLE IF NOT EXISTS videothumbnails (" + 766b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "_id INTEGER PRIMARY KEY," + 767b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "_data TEXT," + 768b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "video_id INTEGER," + 769b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "kind INTEGER," + 770b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "width INTEGER," + 771b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "height INTEGER" + 772b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen ");"); 773b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 774b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen db.execSQL("CREATE INDEX IF NOT EXISTS video_id_index on videothumbnails(video_id);"); 775b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 776b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen db.execSQL("CREATE TRIGGER IF NOT EXISTS videothumbnails_cleanup DELETE ON videothumbnails " + 777b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "BEGIN " + 778b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "SELECT _DELETE_FILE(old._data);" + 779b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "END"); 780b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 781702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 782702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 783702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static void recreateAudioView(SQLiteDatabase db) { 784702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Provides a unified audio/artist/album info view. 785702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Note that views are read-only, so we define a trigger to allow deletes. 786702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP VIEW IF EXISTS audio"); 787702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS audio_delete"); 788702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE VIEW IF NOT EXISTS audio as SELECT * FROM audio_meta " + 789702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "LEFT OUTER JOIN artists ON audio_meta.artist_id=artists.artist_id " + 790702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "LEFT OUTER JOIN albums ON audio_meta.album_id=albums.album_id;"); 791702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 792702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS audio_delete INSTEAD OF DELETE ON audio " + 793702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 794702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE from audio_meta where _id=old._id;" + 795702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE from audio_playlists_map where audio_id=old._id;" + 796702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE from audio_genres_map where audio_id=old._id;" + 797702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 798702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 79995ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen 800702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 801702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Iterate through the rows of a table in a database, ensuring that the bucket_id and 802702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * bucket_display_name columns are correct. 803702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param db 804702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param tableName 805702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 806702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static void updateBucketNames(SQLiteDatabase db, String tableName) { 807702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Rebuild the bucket_display_name column using the natural case rather than lower case. 808702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.beginTransaction(); 809702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 810702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String[] columns = {BaseColumns._ID, MediaColumns.DATA}; 811702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Cursor cursor = db.query(tableName, columns, null, null, null, null, null); 812702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 813702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final int idColumnIndex = cursor.getColumnIndex(BaseColumns._ID); 814702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final int dataColumnIndex = cursor.getColumnIndex(MediaColumns.DATA); 815702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project while (cursor.moveToNext()) { 816702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String data = cursor.getString(dataColumnIndex); 817702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(); 818702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project computeBucketValues(data, values); 819702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int rowId = cursor.getInt(idColumnIndex); 820702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.update(tableName, values, "_id=" + rowId, null); 821702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 822702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 823702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project cursor.close(); 824702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 825702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.setTransactionSuccessful(); 826702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 827702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.endTransaction(); 828702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 829702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 830702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 831702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 832702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Iterate through the rows of a table in a database, ensuring that the 833702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * display name column has a value. 834702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param db 835702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param tableName 836702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 837702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static void updateDisplayName(SQLiteDatabase db, String tableName) { 838702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Fill in default values for null displayName values 839702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.beginTransaction(); 840702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 841702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String[] columns = {BaseColumns._ID, MediaColumns.DATA, MediaColumns.DISPLAY_NAME}; 842702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Cursor cursor = db.query(tableName, columns, null, null, null, null, null); 843702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 844702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final int idColumnIndex = cursor.getColumnIndex(BaseColumns._ID); 845702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final int dataColumnIndex = cursor.getColumnIndex(MediaColumns.DATA); 846702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final int displayNameIndex = cursor.getColumnIndex(MediaColumns.DISPLAY_NAME); 847702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(); 848702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project while (cursor.moveToNext()) { 849702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String displayName = cursor.getString(displayNameIndex); 850702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (displayName == null) { 851702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String data = cursor.getString(dataColumnIndex); 852702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.clear(); 853702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project computeDisplayName(data, values); 854702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int rowId = cursor.getInt(idColumnIndex); 855702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.update(tableName, values, "_id=" + rowId, null); 856702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 857702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 858702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 859702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project cursor.close(); 860702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 861702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.setTransactionSuccessful(); 862702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 863702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.endTransaction(); 864702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 865702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 866702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 867702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param data The input path 868702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param values the content values, where the bucked id name and bucket display name are updated. 869702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 870702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 871702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 872702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static void computeBucketValues(String data, ContentValues values) { 873702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File parentFile = new File(data).getParentFile(); 874702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (parentFile == null) { 875702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project parentFile = new File("/"); 876702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 877702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 878702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Lowercase the path for hashing. This avoids duplicate buckets if the 879702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // filepath case is changed externally. 880702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Keep the original case for display. 881702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String path = parentFile.toString().toLowerCase(); 882702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String name = parentFile.getName(); 883702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 884702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Note: the BUCKET_ID and BUCKET_DISPLAY_NAME attributes are spelled the 885702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // same for both images and video. However, for backwards-compatibility reasons 886702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // there is no common base class. We use the ImageColumns version here 887702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(ImageColumns.BUCKET_ID, path.hashCode()); 888702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(ImageColumns.BUCKET_DISPLAY_NAME, name); 889702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 890702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 891702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 892702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param data The input path 893702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param values the content values, where the display name is updated. 894702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 895702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 896702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static void computeDisplayName(String data, ContentValues values) { 897702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String s = (data == null ? "" : data.toString()); 898702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int idx = s.lastIndexOf('/'); 899702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (idx >= 0) { 900702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project s = s.substring(idx + 1); 901702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 902702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put("_display_name", s); 903702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 904702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 905b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen /** 906b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen * This method blocks until thumbnail is ready. 907b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen * 908b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen * @param thumbUri 909b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen * @return 910b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen */ 911b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private boolean waitForThumbnailReady(Uri origUri) { 912b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen Cursor c = this.query(origUri, new String[] { ImageColumns._ID, ImageColumns.DATA, 913b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen ImageColumns.MINI_THUMB_MAGIC}, null, null, null); 914b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (c == null) return false; 915b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 916b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen boolean result = false; 917b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 918b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (c.moveToFirst()) { 919b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen String path = c.getString(1); 920b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen long magic = c.getLong(2); 921b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 922b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (magic == 0) { 9234d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen MediaThumbRequest req = requestMediaThumbnail(path, origUri, 9244d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen MediaThumbRequest.PRIORITY_HIGH); 925b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen synchronized (req) { 926b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen try { 927b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen while (!req.mDone) { 928b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen req.wait(); 929b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 930b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } catch (InterruptedException e) { 931b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen Log.w(TAG, e); 932b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 933b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 934b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 935b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen result = true; 936b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 937b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen c.close(); 938b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 939b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return result; 940b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 941b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 942b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private boolean queryThumbnail(SQLiteQueryBuilder qb, Uri uri, String table, 943b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen String column, boolean hasThumbnailId) { 944b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen qb.setTables(table); 945b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (hasThumbnailId) { 946b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // For uri dispatched to this method, the 4th path segment is always 947b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // the thumbnail id. 948b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen qb.appendWhere("_id = " + uri.getPathSegments().get(3)); 949b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // client already knows which thumbnail it wants, bypass it. 950b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return true; 951b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 952b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen String origId = uri.getQueryParameter("orig_id"); 953b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // We can't query ready_flag unless we know original id 954b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (origId == null) { 955b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // this could be thumbnail query for other purpose, bypass it. 956b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return true; 957b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 958b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 959b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen boolean needBlocking = "1".equals(uri.getQueryParameter("blocking")); 960b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen Uri origUri = Uri.parse("content://media" + 961b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen uri.getPath().replaceFirst("thumbnails", "media") + "/" + origId); 962b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 963b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (needBlocking && !waitForThumbnailReady(origUri)) { 964b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen Log.w(TAG, "original media doesn't exist."); 965b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return false; 966b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 967b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 968b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (origId != null) { 969b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen qb.appendWhere(column + " = " + origId); 970b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 971b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return true; 972b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 973b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen @SuppressWarnings("fallthrough") 974702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 975702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public Cursor query(Uri uri, String[] projectionIn, String selection, 976702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String[] selectionArgs, String sort) { 977702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int table = URI_MATCHER.match(uri); 978702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 97901a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen // Log.v(TAG, "query: uri="+uri+", selection="+selection); 980702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // handle MEDIA_SCANNER before calling getDatabaseForUri() 981702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (table == MEDIA_SCANNER) { 982702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (mMediaScannerVolume == null) { 983702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return null; 984702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 985702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // create a cursor to return volume currently being scanned by the media scanner 986702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return new MediaScannerCursor(mMediaScannerVolume); 987702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 988702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 989702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 990702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String groupBy = null; 991702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DatabaseHelper database = getDatabaseForUri(uri); 992702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (database == null) { 993702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return null; 994702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 995702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteDatabase db = database.getReadableDatabase(); 996702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 9974574e03055af60fada50481f2b34e19a687d5866Marco Nelissen String limit = uri.getQueryParameter("limit"); 998b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen boolean hasThumbnailId = false; 999702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1000702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (table) { 1001702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA: 1002702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("images"); 1003702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (uri.getQueryParameter("distinct") != null) 1004702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setDistinct(true); 1005702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1006702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // set the project map so that data dir is prepended to _data. 1007702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project //qb.setProjectionMap(mImagesProjectionMap, true); 1008702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1009702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1010702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA_ID: 1011702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("images"); 1012702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (uri.getQueryParameter("distinct") != null) 1013702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setDistinct(true); 1014702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1015702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // set the project map so that data dir is prepended to _data. 1016702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project //qb.setProjectionMap(mImagesProjectionMap, true); 1017702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id = " + uri.getPathSegments().get(3)); 1018702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1019702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1020702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_THUMBNAILS_ID: 1021b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen hasThumbnailId = true; 1022b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case IMAGES_THUMBNAILS: 1023b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (!queryThumbnail(qb, uri, "thumbnails", "image_id", hasThumbnailId)) { 1024b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return null; 1025b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1026702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1027702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1028702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA: 1029702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio "); 1030702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1031702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1032702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID: 1033702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio"); 1034702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id=" + uri.getPathSegments().get(3)); 1035702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1036702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1037702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES: 1038702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_genres"); 1039702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id IN (SELECT genre_id FROM " + 1040702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_genres_map WHERE audio_id = " + 1041702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project uri.getPathSegments().get(3) + ")"); 1042702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1043702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1044702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES_ID: 1045702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_genres"); 1046702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id=" + uri.getPathSegments().get(5)); 1047702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1048702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1049702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS: 1050702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_playlists"); 1051702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id IN (SELECT playlist_id FROM " + 1052702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_playlists_map WHERE audio_id = " + 1053702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project uri.getPathSegments().get(3) + ")"); 1054702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1055702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1056702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS_ID: 1057702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_playlists"); 1058702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id=" + uri.getPathSegments().get(5)); 1059702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1060702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1061702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES: 1062702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_genres"); 1063702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1064702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1065702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID: 1066702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_genres"); 1067702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id=" + uri.getPathSegments().get(3)); 1068702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1069702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1070702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID_MEMBERS: 1071702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio"); 1072702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id IN (SELECT audio_id FROM " + 1073702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_genres_map WHERE genre_id = " + 1074702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project uri.getPathSegments().get(3) + ")"); 1075702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1076702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1077702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID_MEMBERS_ID: 1078702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio"); 1079702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id=" + uri.getPathSegments().get(5)); 1080702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1081702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1082702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS: 1083702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_playlists"); 1084702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1085702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1086702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID: 1087702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_playlists"); 1088702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id=" + uri.getPathSegments().get(3)); 1089702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1090702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1091702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS: 109297e61d89d90a1bd6989a254660aa80553662e002Marco Nelissen if (projectionIn != null) { 109397e61d89d90a1bd6989a254660aa80553662e002Marco Nelissen for (int i = 0; i < projectionIn.length; i++) { 109497e61d89d90a1bd6989a254660aa80553662e002Marco Nelissen if (projectionIn[i].equals("_id")) { 109597e61d89d90a1bd6989a254660aa80553662e002Marco Nelissen projectionIn[i] = "audio_playlists_map._id AS _id"; 109697e61d89d90a1bd6989a254660aa80553662e002Marco Nelissen } 1097702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1098702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1099702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_playlists_map, audio"); 1100702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("audio._id = audio_id AND playlist_id = " 1101702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project + uri.getPathSegments().get(3)); 1102702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1103702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1104702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS_ID: 1105702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio"); 1106702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id=" + uri.getPathSegments().get(5)); 1107702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1108702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1109702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA: 1110702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("video"); 1111702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1112702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1113702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA_ID: 1114702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("video"); 1115702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id=" + uri.getPathSegments().get(3)); 1116702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1117702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1118b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case VIDEO_THUMBNAILS_ID: 1119b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen hasThumbnailId = true; 1120b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case VIDEO_THUMBNAILS: 1121b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (!queryThumbnail(qb, uri, "videothumbnails", "video_id", hasThumbnailId)) { 1122b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return null; 1123b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1124b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen break; 1125b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1126702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ARTISTS: 1127702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("artist_info"); 1128702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1129702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1130702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ARTISTS_ID: 1131702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("artist_info"); 1132702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id=" + uri.getPathSegments().get(3)); 1133702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1134702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1135702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ARTISTS_ID_ALBUMS: 1136702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String aid = uri.getPathSegments().get(3); 1137702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio LEFT OUTER JOIN album_art ON" + 1138702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " audio.album_id=album_art.album_id"); 1139702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("is_music=1 AND audio.album_id IN (SELECT album_id FROM " + 1140702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "artists_albums_map WHERE artist_id = " + 1141702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project aid + ")"); 1142702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project groupBy = "audio.album_id"; 1143702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Albums.NUMBER_OF_SONGS_FOR_ARTIST, 1144702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "count(CASE WHEN artist_id==" + aid + " THEN 'foo' ELSE NULL END) AS " + 1145702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.Audio.Albums.NUMBER_OF_SONGS_FOR_ARTIST); 1146702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setProjectionMap(sArtistAlbumsMap); 1147702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1148702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1149702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ALBUMS: 1150702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("album_info"); 1151702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1152702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1153702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ALBUMS_ID: 1154702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("album_info"); 1155702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id=" + uri.getPathSegments().get(3)); 1156702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1157702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1158702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ALBUMART_ID: 1159702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("album_art"); 1160702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("album_id=" + uri.getPathSegments().get(3)); 1161702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1162702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1163a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen case AUDIO_SEARCH_LEGACY: 1164a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen Log.w(TAG, "Legacy media search Uri used. Please update your code."); 1165a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // fall through 1166a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen case AUDIO_SEARCH_FANCY: 1167a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen case AUDIO_SEARCH_BASIC: 1168a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen return doAudioSearch(db, qb, uri, projectionIn, selection, selectionArgs, sort, 11694574e03055af60fada50481f2b34e19a687d5866Marco Nelissen table, limit); 1170702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1171702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project default: 1172702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalStateException("Unknown URL: " + uri.toString()); 1173702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1174702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 11754d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen // Log.v(TAG, "query = "+ qb.buildQuery(projectionIn, selection, selectionArgs, groupBy, null, sort, limit)); 1176702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Cursor c = qb.query(db, projectionIn, selection, 11774574e03055af60fada50481f2b34e19a687d5866Marco Nelissen selectionArgs, groupBy, null, sort, limit); 1178b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1179702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (c != null) { 1180702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project c.setNotificationUri(getContext().getContentResolver(), uri); 1181702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1182b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1183702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return c; 1184702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1185702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1186702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private Cursor doAudioSearch(SQLiteDatabase db, SQLiteQueryBuilder qb, 1187702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Uri uri, String[] projectionIn, String selection, 11884574e03055af60fada50481f2b34e19a687d5866Marco Nelissen String[] selectionArgs, String sort, int mode, 11894574e03055af60fada50481f2b34e19a687d5866Marco Nelissen String limit) { 1190702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1191a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen String mSearchString = uri.toString().endsWith("/") ? "" : uri.getLastPathSegment(); 1192702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mSearchString = mSearchString.replaceAll(" ", " ").trim().toLowerCase(); 1193702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1194702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String [] searchWords = mSearchString.length() > 0 ? 1195702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mSearchString.split(" ") : new String[0]; 1196a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen String [] wildcardWords = new String[searchWords.length]; 1197702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Collator col = Collator.getInstance(); 1198702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project col.setStrength(Collator.PRIMARY); 1199702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int len = searchWords.length; 1200702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project for (int i = 0; i < len; i++) { 1201702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Because we match on individual words here, we need to remove words 1202702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // like 'a' and 'the' that aren't part of the keys. 1203a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen wildcardWords[i] = 1204702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project (searchWords[i].equals("a") || searchWords[i].equals("an") || 1205702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project searchWords[i].equals("the")) ? "%" : 1206702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project '%' + MediaStore.Audio.keyFor(searchWords[i]) + '%'; 1207702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1208702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1209a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen String where = ""; 1210a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen for (int i = 0; i < searchWords.length; i++) { 1211a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen if (i == 0) { 1212a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen where = "match LIKE ?"; 1213a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen } else { 1214a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen where += " AND match LIKE ?"; 1215702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1216702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1217702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1218a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen qb.setTables("search"); 1219a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen String [] cols; 1220a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen if (mode == AUDIO_SEARCH_FANCY) { 1221a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen cols = mSearchColsFancy; 1222a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen } else if (mode == AUDIO_SEARCH_BASIC) { 1223a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen cols = mSearchColsBasic; 1224a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen } else { 1225a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen cols = mSearchColsLegacy; 1226702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 12274574e03055af60fada50481f2b34e19a687d5866Marco Nelissen return qb.query(db, cols, where, wildcardWords, null, null, null, limit); 1228702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1229702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1230702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 1231702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public String getType(Uri url) 1232702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project { 1233702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (URI_MATCHER.match(url)) { 1234702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA_ID: 1235702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID: 1236702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID_MEMBERS_ID: 1237702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS_ID: 1238702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA_ID: 1239702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Cursor c = query(url, MIME_TYPE_PROJECTION, null, null, null); 1240702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (c != null && c.getCount() == 1) { 1241702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project c.moveToFirst(); 1242702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String mimeType = c.getString(1); 1243702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project c.deactivate(); 1244702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return mimeType; 1245702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1246702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1247702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1248702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA: 1249702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_THUMBNAILS: 1250702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Images.Media.CONTENT_TYPE; 1251702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_THUMBNAILS_ID: 1252702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return "image/jpeg"; 1253702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1254702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA: 1255702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID_MEMBERS: 1256702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS: 1257702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Audio.Media.CONTENT_TYPE; 1258702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1259702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES: 1260702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES: 1261702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Audio.Genres.CONTENT_TYPE; 1262702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID: 1263702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES_ID: 1264702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Audio.Genres.ENTRY_CONTENT_TYPE; 1265702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS: 1266702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS: 1267702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Audio.Playlists.CONTENT_TYPE; 1268702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID: 1269702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS_ID: 1270702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Audio.Playlists.ENTRY_CONTENT_TYPE; 1271702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1272702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA: 1273702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Video.Media.CONTENT_TYPE; 1274702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1275702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalStateException("Unknown URL"); 1276702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1277702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1278702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 1279702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Ensures there is a file in the _data column of values, if one isn't 1280702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * present a new file is created. 1281702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 1282702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param initialValues the values passed to insert by the caller 1283702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @return the new values 1284702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 1285702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private ContentValues ensureFile(boolean internal, ContentValues initialValues, 1286702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String preferredExtension, String directoryName) { 1287702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values; 1288702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String file = initialValues.getAsString("_data"); 1289702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (TextUtils.isEmpty(file)) { 1290702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project file = generateFileName(internal, preferredExtension, directoryName); 1291702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values = new ContentValues(initialValues); 1292702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put("_data", file); 1293702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 1294702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values = initialValues; 1295702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1296702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1297702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!ensureFileExists(file)) { 1298702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalStateException("Unable to create new file: " + file); 1299702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1300702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return values; 1301702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1302702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1303702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 1304702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public int bulkInsert(Uri uri, ContentValues values[]) { 1305702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int match = URI_MATCHER.match(uri); 1306702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (match == VOLUMES) { 1307702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return super.bulkInsert(uri, values); 1308702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1309702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DatabaseHelper database = getDatabaseForUri(uri); 1310702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (database == null) { 1311702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException( 1312702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Unknown URI: " + uri); 1313702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1314702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteDatabase db = database.getWritableDatabase(); 1315702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.beginTransaction(); 1316702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int numInserted = 0; 1317702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 1318702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int len = values.length; 1319702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project for (int i = 0; i < len; i++) { 1320702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project insertInternal(uri, values[i]); 1321702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1322702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project numInserted = len; 1323702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.setTransactionSuccessful(); 1324702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 1325702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.endTransaction(); 1326702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1327702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 1328702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return numInserted; 1329702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1330702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1331702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 1332702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public Uri insert(Uri uri, ContentValues initialValues) 1333702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project { 1334702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Uri newUri = insertInternal(uri, initialValues); 1335702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (newUri != null) { 1336702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 1337702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1338702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return newUri; 1339702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1340702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1341702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private Uri insertInternal(Uri uri, ContentValues initialValues) { 1342702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long rowId; 1343702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int match = URI_MATCHER.match(uri); 1344702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1345b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // Log.v(TAG, "insertInternal: "+uri+", initValues="+initialValues); 1346702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // handle MEDIA_SCANNER before calling getDatabaseForUri() 1347702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (match == MEDIA_SCANNER) { 1348702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mMediaScannerVolume = initialValues.getAsString(MediaStore.MEDIA_SCANNER_VOLUME); 1349702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return MediaStore.getMediaScannerUri(); 1350702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1351702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1352702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Uri newUri = null; 1353702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DatabaseHelper database = getDatabaseForUri(uri); 1354702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (database == null && match != VOLUMES) { 1355702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException( 1356702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Unknown URI: " + uri); 1357702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1358702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteDatabase db = (match == VOLUMES ? null : database.getWritableDatabase()); 1359702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1360702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (initialValues == null) { 1361702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project initialValues = new ContentValues(); 1362702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1363702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1364702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (match) { 1365702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA: { 1366702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = ensureFile(database.mInternal, initialValues, ".jpg", "DCIM/Camera"); 1367702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1368702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(MediaStore.MediaColumns.DATE_ADDED, System.currentTimeMillis() / 1000); 1369702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String data = values.getAsString(MediaColumns.DATA); 1370702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (! values.containsKey(MediaColumns.DISPLAY_NAME)) { 1371702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project computeDisplayName(data, values); 1372702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1373702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project computeBucketValues(data, values); 1374702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert("images", "name", values); 1375702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1376702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 1377702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId( 1378702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Images.Media.getContentUri(uri.getPathSegments().get(0)), rowId); 13794d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen requestMediaThumbnail(data, newUri, MediaThumbRequest.PRIORITY_NORMAL); 1380702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1381702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1382702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1383702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1384b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // This will be triggered by requestMediaThumbnail (see getThumbnailUri) 1385702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_THUMBNAILS: { 1386b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen ContentValues values = ensureFile(database.mInternal, initialValues, ".jpg", 1387b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "DCIM/.thumbnails"); 1388702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert("thumbnails", "name", values); 1389702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 1390702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(Images.Thumbnails. 1391702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContentUri(uri.getPathSegments().get(0)), rowId); 1392702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1393702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1394702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1395702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1396b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // This is currently only used by MICRO_KIND video thumbnail (see getThumbnailUri) 1397b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case VIDEO_THUMBNAILS: { 1398b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen ContentValues values = ensureFile(database.mInternal, initialValues, ".jpg", 1399b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "DCIM/.thumbnails"); 1400b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen rowId = db.insert("videothumbnails", "name", values); 1401b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (rowId > 0) { 1402b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen newUri = ContentUris.withAppendedId(Video.Thumbnails. 1403b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen getContentUri(uri.getPathSegments().get(0)), rowId); 1404b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1405b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen break; 1406b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1407b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1408702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA: { 1409702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // SQLite Views are read-only, so we need to deconstruct this 1410702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // insert and do inserts into the underlying tables. 1411702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // If doing this here turns out to be a performance bottleneck, 1412702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // consider moving this to native code and using triggers on 1413702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // the view. 1414702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(initialValues); 1415702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1416702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Insert the artist into the artist table and remove it from 1417702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // the input values 1418702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Object so = values.get("artist"); 1419702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String s = (so == null ? "" : so.toString()); 1420702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.remove("artist"); 1421702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long artistRowId; 1422702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project HashMap<String, Long> artistCache = database.mArtistCache; 142359948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen String path = values.getAsString("_data"); 1424702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized(artistCache) { 1425702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Long temp = artistCache.get(s); 1426702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (temp == null) { 1427702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project artistRowId = getKeyIdForName(db, "artists", "artist_key", "artist", 1428a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen s, s, path, 0, null, artistCache, uri); 1429702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 1430702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project artistRowId = temp.longValue(); 1431702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1432702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1433a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen String artist = s; 1434702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1435702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Do the same for the album field 1436702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project so = values.get("album"); 1437702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project s = (so == null ? "" : so.toString()); 1438702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.remove("album"); 1439702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long albumRowId; 1440702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project HashMap<String, Long> albumCache = database.mAlbumCache; 1441702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized(albumCache) { 144259948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen int albumhash = path.substring(0, path.lastIndexOf('/')).hashCode(); 144359948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen String cacheName = s + albumhash; 144459948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen Long temp = albumCache.get(cacheName); 1445702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (temp == null) { 1446702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project albumRowId = getKeyIdForName(db, "albums", "album_key", "album", 1447a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen s, cacheName, path, albumhash, artist, albumCache, uri); 1448702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 1449702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project albumRowId = temp; 1450702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1451702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1452702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1453702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put("artist_id", Integer.toString((int)artistRowId)); 1454702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put("album_id", Integer.toString((int)albumRowId)); 1455702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project so = values.getAsString("title"); 1456702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project s = (so == null ? "" : so.toString()); 1457702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put("title_key", MediaStore.Audio.keyFor(s)); 1458358cfed9391de9b39ecb2a3dbefcf5e392915954Marco Nelissen // do a final trim of the title, in case it started with the special 1459358cfed9391de9b39ecb2a3dbefcf5e392915954Marco Nelissen // "sort first" character (ascii \001) 1460358cfed9391de9b39ecb2a3dbefcf5e392915954Marco Nelissen values.remove("title"); 1461358cfed9391de9b39ecb2a3dbefcf5e392915954Marco Nelissen values.put("title", s.trim()); 1462702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1463702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project computeDisplayName(values.getAsString("_data"), values); 1464702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(MediaStore.MediaColumns.DATE_ADDED, System.currentTimeMillis() / 1000); 1465702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1466702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert("audio_meta", "duration", values); 1467702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 1468702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(Audio.Media.getContentUri(uri.getPathSegments().get(0)), rowId); 1469702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1470702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1471702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1472702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1473702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES: { 1474702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Long audioId = Long.parseLong(uri.getPathSegments().get(2)); 1475702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(initialValues); 1476702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(Audio.Genres.Members.AUDIO_ID, audioId); 1477702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert("audio_playlists_map", "genre_id", values); 1478702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 1479702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(uri, rowId); 1480702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1481702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1482702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1483702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1484702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS: { 1485702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Long audioId = Long.parseLong(uri.getPathSegments().get(2)); 1486702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(initialValues); 1487702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(Audio.Playlists.Members.AUDIO_ID, audioId); 1488702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert("audio_playlists_map", "playlist_id", 1489702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values); 1490702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 1491702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(uri, rowId); 1492702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1493702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1494702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1495702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1496702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES: { 1497702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert("audio_genres", "audio_id", initialValues); 1498702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 1499702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(Audio.Genres.getContentUri(uri.getPathSegments().get(0)), rowId); 1500702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1501702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1502702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1503702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1504702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID_MEMBERS: { 1505702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Long genreId = Long.parseLong(uri.getPathSegments().get(3)); 1506702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(initialValues); 1507702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(Audio.Genres.Members.GENRE_ID, genreId); 1508702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert("audio_genres_map", "genre_id", values); 1509702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 1510702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(uri, rowId); 1511702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1512702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1513702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1514702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1515702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS: { 1516702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(initialValues); 1517702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(MediaStore.Audio.Playlists.DATE_ADDED, System.currentTimeMillis() / 1000); 1518702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert("audio_playlists", "name", initialValues); 1519702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 1520702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(Audio.Playlists.getContentUri(uri.getPathSegments().get(0)), rowId); 1521702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1522702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1523702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1524702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1525702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID: 1526702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS: { 1527702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Long playlistId = Long.parseLong(uri.getPathSegments().get(3)); 1528702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(initialValues); 1529702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(Audio.Playlists.Members.PLAYLIST_ID, playlistId); 1530702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert("audio_playlists_map", "playlist_id", 1531702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values); 1532702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 1533702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(uri, rowId); 1534702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1535702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1536702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1537702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1538702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA: { 1539702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = ensureFile(database.mInternal, initialValues, ".3gp", "video"); 1540702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String data = values.getAsString("_data"); 1541702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project computeDisplayName(data, values); 1542702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project computeBucketValues(data, values); 1543702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(MediaStore.MediaColumns.DATE_ADDED, System.currentTimeMillis() / 1000); 1544702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert("video", "artist", values); 1545702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 1546b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen newUri = ContentUris.withAppendedId(Video.Media.getContentUri( 1547b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen uri.getPathSegments().get(0)), rowId); 1548b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen requestMediaThumbnail(data, newUri, 0); 1549702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1550702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1551702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1552702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1553702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ALBUMART: 1554702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (database.mInternal) { 1555702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException("no internal album art allowed"); 1556702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1557702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = null; 1558702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 1559702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values = ensureFile(false, initialValues, "", ALBUM_THUMB_FOLDER); 1560702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } catch (IllegalStateException ex) { 1561702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // probably no more room to store albumthumbs 1562702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values = initialValues; 1563702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1564702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert("album_art", "_data", values); 1565702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 1566702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(uri, rowId); 1567702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1568702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1569702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1570702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VOLUMES: 1571702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return attachVolume(initialValues.getAsString("name")); 1572702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1573702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project default: 1574702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException("Invalid URI " + uri); 1575702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1576702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1577702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return newUri; 1578702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1579702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 15804d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen private MediaThumbRequest requestMediaThumbnail(String path, Uri uri, int priority) { 1581b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen synchronized (mMediaThumbQueue) { 158201a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen //Log.v(TAG, "requestMediaThumbnail: "+path+", "+uri+", magic="+magic); 1583b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen MediaThumbRequest req = new MediaThumbRequest( 15844d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen getContext().getContentResolver(), path, uri, priority); 1585b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen mMediaThumbQueue.add(req); 1586b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // Trigger the handler. 1587b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen Message msg = mThumbHandler.obtainMessage(IMAGE_THUMB); 1588b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen msg.sendToTarget(); 1589b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return req; 1590b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1591b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1592b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1593702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private String generateFileName(boolean internal, String preferredExtension, String directoryName) 1594702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project { 1595702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // create a random file 1596702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String name = String.valueOf(System.currentTimeMillis()); 1597702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1598702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (internal) { 1599702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException("Writing to internal storage is not supported."); 1600702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project// return Environment.getDataDirectory() 1601702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project// + "/" + directoryName + "/" + name + preferredExtension; 1602702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 1603702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Environment.getExternalStorageDirectory() 1604702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project + "/" + directoryName + "/" + name + preferredExtension; 1605702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1606702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1607702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1608702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private boolean ensureFileExists(String path) { 1609702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File file = new File(path); 1610702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (file.exists()) { 1611702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return true; 1612702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 1613702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // we will not attempt to create the first directory in the path 1614702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // (for example, do not create /sdcard if the SD card is not mounted) 1615702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int secondSlash = path.indexOf('/', 1); 1616702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (secondSlash < 1) return false; 1617702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String directoryPath = path.substring(0, secondSlash); 1618702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File directory = new File(directoryPath); 1619702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!directory.exists()) 1620702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return false; 1621702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project file.getParentFile().mkdirs(); 1622702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 1623702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return file.createNewFile(); 1624702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } catch(IOException ioe) { 1625702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Log.e(TAG, "File creation failed", ioe); 1626702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1627702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return false; 1628702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1629702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1630702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1631702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final class GetTableAndWhereOutParameter { 1632702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public String table; 1633702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public String where; 1634702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1635702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1636702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project static final GetTableAndWhereOutParameter sGetTableAndWhereParam = 1637702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project new GetTableAndWhereOutParameter(); 1638702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1639702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private void getTableAndWhere(Uri uri, int match, String userWhere, 1640702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project GetTableAndWhereOutParameter out) { 1641702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String where = null; 1642702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (match) { 16439f02f449f6951b15bb9daaa3fc6e1d648b36b08aGoodwin case IMAGES_MEDIA: 16449f02f449f6951b15bb9daaa3fc6e1d648b36b08aGoodwin out.table = "images"; 16459f02f449f6951b15bb9daaa3fc6e1d648b36b08aGoodwin break; 16469f02f449f6951b15bb9daaa3fc6e1d648b36b08aGoodwin 1647702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA_ID: 1648702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "images"; 1649702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "_id = " + uri.getPathSegments().get(3); 1650702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1651702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1652b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case IMAGES_THUMBNAILS_ID: 1653b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen where = "_id=" + uri.getPathSegments().get(3); 1654b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case IMAGES_THUMBNAILS: 1655b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen out.table = "thumbnails"; 1656b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen break; 1657b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1658702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA: 1659702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio"; 1660702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1661702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1662702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID: 1663702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio"; 1664702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "_id=" + uri.getPathSegments().get(3); 1665702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1666702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1667702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES: 1668702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_genres"; 1669702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "audio_id=" + uri.getPathSegments().get(3); 1670702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1671702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1672702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES_ID: 1673702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_genres"; 1674702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "audio_id=" + uri.getPathSegments().get(3) + 1675702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " AND genre_id=" + uri.getPathSegments().get(5); 1676702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1677702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1678702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS: 1679702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_playlists"; 1680702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "audio_id=" + uri.getPathSegments().get(3); 1681702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1682702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1683702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS_ID: 1684702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_playlists"; 1685702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "audio_id=" + uri.getPathSegments().get(3) + 1686702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " AND playlists_id=" + uri.getPathSegments().get(5); 1687702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1688702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1689702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES: 1690702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_genres"; 1691702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1692702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1693702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID: 1694702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_genres"; 1695702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "_id=" + uri.getPathSegments().get(3); 1696702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1697702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1698702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID_MEMBERS: 1699702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_genres"; 1700702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "genre_id=" + uri.getPathSegments().get(3); 1701702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1702702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1703702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID_MEMBERS_ID: 1704702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_genres"; 1705702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "genre_id=" + uri.getPathSegments().get(3) + 1706702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " AND audio_id =" + uri.getPathSegments().get(5); 1707702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1708702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1709702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS: 1710702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_playlists"; 1711702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1712702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1713702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID: 1714702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_playlists"; 1715702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "_id=" + uri.getPathSegments().get(3); 1716702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1717702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1718702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS: 1719702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_playlists_map"; 1720702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "playlist_id=" + uri.getPathSegments().get(3); 1721702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1722702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1723702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS_ID: 1724702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_playlists_map"; 1725702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "playlist_id=" + uri.getPathSegments().get(3) + 1726702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " AND _id=" + uri.getPathSegments().get(5); 1727702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1728702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1729702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ALBUMART_ID: 1730702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "album_art"; 1731702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "album_id=" + uri.getPathSegments().get(3); 1732702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1733702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1734702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA: 1735702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "video"; 1736702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1737702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1738702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA_ID: 1739702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "video"; 1740702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "_id=" + uri.getPathSegments().get(3); 1741702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1742702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1743b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case VIDEO_THUMBNAILS_ID: 1744b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen where = "_id=" + uri.getPathSegments().get(3); 1745b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case VIDEO_THUMBNAILS: 1746b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen out.table = "videothumbnails"; 1747b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen break; 1748b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1749702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project default: 1750702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException( 1751702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Unknown or unsupported URL: " + uri.toString()); 1752702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1753702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1754702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Add in the user requested WHERE clause, if needed 1755702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!TextUtils.isEmpty(userWhere)) { 1756702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!TextUtils.isEmpty(where)) { 1757702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.where = where + " AND (" + userWhere + ")"; 1758702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 1759702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.where = userWhere; 1760702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1761702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 1762702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.where = where; 1763702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1764702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1765702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1766702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 1767702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public int delete(Uri uri, String userWhere, String[] whereArgs) { 1768702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int count; 1769702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int match = URI_MATCHER.match(uri); 1770702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1771702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // handle MEDIA_SCANNER before calling getDatabaseForUri() 1772702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (match == MEDIA_SCANNER) { 1773702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (mMediaScannerVolume == null) { 1774702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return 0; 1775702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1776702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mMediaScannerVolume = null; 1777702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return 1; 1778702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1779702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1780702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (match != VOLUMES_ID) { 1781702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DatabaseHelper database = getDatabaseForUri(uri); 1782702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (database == null) { 1783702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException( 1784702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Unknown URI: " + uri); 1785702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1786702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteDatabase db = database.getWritableDatabase(); 1787702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1788702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized (sGetTableAndWhereParam) { 1789702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getTableAndWhere(uri, match, userWhere, sGetTableAndWhereParam); 1790702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (match) { 1791702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA: 1792702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID: 1793702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count = db.delete("audio_meta", 1794702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sGetTableAndWhereParam.where, whereArgs); 1795702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1796702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project default: 1797702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count = db.delete(sGetTableAndWhereParam.table, 1798702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sGetTableAndWhereParam.where, whereArgs); 1799702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1800702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1801702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 1802702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1803702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 1804702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project detachVolume(uri); 1805702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count = 1; 1806702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1807702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1808702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return count; 1809702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1810702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1811702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 1812702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public int update(Uri uri, ContentValues initialValues, String userWhere, 1813702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String[] whereArgs) { 1814702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int count; 1815b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // Log.v(TAG, "update for uri="+uri+", initValues="+initialValues); 1816702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int match = URI_MATCHER.match(uri); 1817702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DatabaseHelper database = getDatabaseForUri(uri); 1818702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (database == null) { 1819702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException( 1820702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Unknown URI: " + uri); 1821702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1822702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteDatabase db = database.getWritableDatabase(); 1823702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1824702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized (sGetTableAndWhereParam) { 1825702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getTableAndWhere(uri, match, userWhere, sGetTableAndWhereParam); 1826702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1827702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (match) { 1828702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA: 1829702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID: 1830702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project { 1831702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(initialValues); 1832702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Insert the artist into the artist table and remove it from 1833702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // the input values 1834a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen String artist = values.getAsString("artist"); 1835a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen if (artist != null) { 1836702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.remove("artist"); 1837702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long artistRowId; 1838702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project HashMap<String, Long> artistCache = database.mArtistCache; 1839702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized(artistCache) { 1840a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen Long temp = artistCache.get(artist); 1841702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (temp == null) { 1842702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project artistRowId = getKeyIdForName(db, "artists", "artist_key", "artist", 1843a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen artist, artist, null, 0, null, artistCache, uri); 1844702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 1845702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project artistRowId = temp.longValue(); 1846702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1847702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1848702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put("artist_id", Integer.toString((int)artistRowId)); 1849702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1850702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 185159948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // Do the same for the album field. 1852a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen String so = values.getAsString("album"); 1853702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (so != null) { 185459948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen String path = values.getAsString("_data"); 185559948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen int albumHash = 0; 185659948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen if (path == null) { 185759948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // If the path is null, we don't have a hash for the file in question. 185859948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen Log.w(TAG, "Update without specified path."); 185959948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen } else { 186059948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen albumHash = path.substring(0, path.lastIndexOf('/')).hashCode(); 186159948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen } 1862702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String s = so.toString(); 1863702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.remove("album"); 1864702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long albumRowId; 1865702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project HashMap<String, Long> albumCache = database.mAlbumCache; 1866702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized(albumCache) { 186759948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen String cacheName = s + albumHash; 186859948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen Long temp = albumCache.get(cacheName); 1869702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (temp == null) { 1870702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project albumRowId = getKeyIdForName(db, "albums", "album_key", "album", 1871a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen s, cacheName, path, albumHash, artist, albumCache, uri); 1872702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 1873702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project albumRowId = temp.longValue(); 1874702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1875702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1876702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put("album_id", Integer.toString((int)albumRowId)); 1877702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1878702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1879702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // don't allow the title_key field to be updated directly 1880702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.remove("title_key"); 1881702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // If the title field is modified, update the title_key 1882702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project so = values.getAsString("title"); 1883702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (so != null) { 1884702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String s = so.toString(); 1885702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put("title_key", MediaStore.Audio.keyFor(s)); 1886e96c1d9637e89b5f99c7002fd06f7f35a9164849Marco Nelissen // do a final trim of the title, in case it started with the special 1887e96c1d9637e89b5f99c7002fd06f7f35a9164849Marco Nelissen // "sort first" character (ascii \001) 1888e96c1d9637e89b5f99c7002fd06f7f35a9164849Marco Nelissen values.remove("title"); 1889e96c1d9637e89b5f99c7002fd06f7f35a9164849Marco Nelissen values.put("title", s.trim()); 1890702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1891702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1892702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count = db.update("audio_meta", values, sGetTableAndWhereParam.where, 1893702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project whereArgs); 1894702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1895702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1896702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA: 1897702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA_ID: 1898702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA: 1899702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA_ID: 1900702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project { 1901702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(initialValues); 1902702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Don't allow bucket id or display name to be updated directly. 1903702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // The same names are used for both images and table columns, so 1904702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // we use the ImageColumns constants here. 1905702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.remove(ImageColumns.BUCKET_ID); 1906702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.remove(ImageColumns.BUCKET_DISPLAY_NAME); 1907702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // If the data is being modified update the bucket values 1908702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String data = values.getAsString(MediaColumns.DATA); 1909702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (data != null) { 1910702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project computeBucketValues(data, values); 1911702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1912702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count = db.update(sGetTableAndWhereParam.table, values, 1913702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sGetTableAndWhereParam.where, whereArgs); 191401a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen // if this is a request from MediaScanner, DATA should contains file path 191501a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen // we only process update request from media scanner, otherwise the requests 191601a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen // could be duplicate. 191701a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen if (count > 0 && values.getAsString(MediaStore.MediaColumns.DATA) != null) { 191801a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen Cursor c = db.query(sGetTableAndWhereParam.table, 191901a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen READY_FLAG_PROJECTION, sGetTableAndWhereParam.where, 192001a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen whereArgs, null, null, null); 1921b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (c != null) { 1922b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen while (c.moveToNext()) { 192301a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen long magic = c.getLong(2); 192401a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen if (magic == 0) { 19254d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen requestMediaThumbnail(c.getString(1), uri, 19264d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen MediaThumbRequest.PRIORITY_NORMAL); 1927b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1928b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1929b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen c.close(); 1930b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1931b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1932702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1933702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1934702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project default: 1935702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count = db.update(sGetTableAndWhereParam.table, initialValues, 1936702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sGetTableAndWhereParam.where, whereArgs); 1937702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1938702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1939702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1940702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (count > 0) { 1941702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 1942702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1943702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return count; 1944702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1945702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1946702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final String[] openFileColumns = new String[] { 1947702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.MediaColumns.DATA, 1948702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project }; 1949702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1950702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 1951702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public ParcelFileDescriptor openFile(Uri uri, String mode) 1952702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throws FileNotFoundException { 195371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen 1954702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ParcelFileDescriptor pfd = null; 195571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen 195671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (URI_MATCHER.match(uri) == AUDIO_ALBUMART_FILE_ID) { 195771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // get album art for the specified media file 195871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen DatabaseHelper database = getDatabaseForUri(uri); 195971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (database == null) { 196071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen throw new IllegalStateException("Couldn't open database for " + uri); 196171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 196271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen SQLiteDatabase db = database.getReadableDatabase(); 196371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 196471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen int songid = Integer.parseInt(uri.getPathSegments().get(3)); 196571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen qb.setTables("audio_meta"); 196671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen qb.appendWhere("_id=" + songid); 196771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen Cursor c = qb.query(db, 196871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen new String [] { 196971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen MediaStore.Audio.Media.DATA, 197071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen MediaStore.Audio.Media.ALBUM_ID }, 197171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen null, null, null, null, null); 197271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (c.moveToFirst()) { 197371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen String audiopath = c.getString(0); 197471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen int albumid = c.getInt(1); 197571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // Try to get existing album art for this album first, which 197671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // could possibly have been obtained from a different file. 197771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // If that fails, try to get it from this specific file. 197871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen Uri newUri = ContentUris.withAppendedId(ALBUMART_URI, albumid); 197971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen try { 198071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen pfd = openFile(newUri, mode); // recursive call 198171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } catch (FileNotFoundException ex) { 198271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // That didn't work, now try to get it from the specific file 198371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen pfd = getThumb(db, audiopath, albumid, null); 198471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 198571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 198671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen c.close(); 198771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen return pfd; 198871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 198971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen 1990702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 1991702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project pfd = openFileHelper(uri, mode); 1992702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } catch (FileNotFoundException ex) { 199371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (mode.contains("w")) { 199471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // if the file couldn't be created, we shouldn't extract album art 199571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen throw ex; 199671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 199771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen 1998702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (URI_MATCHER.match(uri) == AUDIO_ALBUMART_ID) { 1999702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Tried to open an album art file which does not exist. Regenerate. 2000702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DatabaseHelper database = getDatabaseForUri(uri); 2001702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (database == null) { 2002702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw ex; 2003702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2004702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteDatabase db = database.getReadableDatabase(); 2005702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 2006702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int albumid = Integer.parseInt(uri.getPathSegments().get(3)); 200771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen qb.setTables("audio_meta"); 2008702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("album_id=" + albumid); 2009702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Cursor c = qb.query(db, 2010702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project new String [] { 2011702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.Audio.Media.DATA }, 2012702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project null, null, null, null, null); 201371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (c.moveToFirst()) { 2014702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String audiopath = c.getString(0); 201571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen pfd = getThumb(db, audiopath, albumid, uri); 2016702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2017702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project c.close(); 2018702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 201971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (pfd == null) { 202071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen throw ex; 202171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 2022702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2023702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return pfd; 2024702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2025702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2026702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private class Worker implements Runnable { 2027702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private final Object mLock = new Object(); 2028702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private Looper mLooper; 2029702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2030702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Worker(String name) { 2031702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Thread t = new Thread(null, this, name); 2032702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project t.start(); 2033702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized (mLock) { 2034702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project while (mLooper == null) { 2035702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 2036702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mLock.wait(); 2037702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } catch (InterruptedException ex) { 2038702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2039702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2040702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2041702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2042702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2043702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public Looper getLooper() { 2044702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return mLooper; 2045702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2046702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2047702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public void run() { 2048702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized (mLock) { 2049f75dba4941649c19bfe9c14a6ef152af21346056Marco Nelissen Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); 2050702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Looper.prepare(); 2051702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mLooper = Looper.myLooper(); 2052702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mLock.notifyAll(); 2053702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2054702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Looper.loop(); 2055702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2056702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2057702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public void quit() { 2058702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mLooper.quit(); 2059702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2060702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2061702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2062702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private class ThumbData { 2063702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteDatabase db; 2064702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String path; 2065702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long album_id; 2066702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Uri albumart_uri; 2067702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2068702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2069a9c4e330dacb37cfffa9c00f7da83cafde4accefMarco Nelissen private void makeThumbAsync(SQLiteDatabase db, String path, long album_id) { 20708a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber synchronized (mPendingThumbs) { 20718a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (mPendingThumbs.contains(path)) { 20728a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // There's already a request to make an album art thumbnail 20738a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // for this audio file in the queue. 20748a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber return; 20758a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 20768a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 20778a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber mPendingThumbs.add(path); 20788a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 20798a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 2080702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ThumbData d = new ThumbData(); 2081702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project d.db = db; 2082702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project d.path = path; 2083702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project d.album_id = album_id; 2084a9c4e330dacb37cfffa9c00f7da83cafde4accefMarco Nelissen d.albumart_uri = ContentUris.withAppendedId(mAlbumArtBaseUri, album_id); 20858a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 20868a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // Instead of processing thumbnail requests in the order they were 20878a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // received we instead process them stack-based, i.e. LIFO. 20888a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // The idea behind this is that the most recently requested thumbnails 20898a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // are most likely the ones still in the user's view, whereas those 20908a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // requested earlier may have already scrolled off. 20918a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber synchronized (mThumbRequestStack) { 20928a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber mThumbRequestStack.push(d); 20938a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 20948a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 20958a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // Trigger the handler. 2096b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen Message msg = mThumbHandler.obtainMessage(ALBUM_THUMB); 2097702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project msg.sendToTarget(); 2098702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2099702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 21008a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // Extract compressed image data from the audio file itself or, if that fails, 21018a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // look for a file "AlbumArt.jpg" in the containing directory. 21028a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber private static byte[] getCompressedAlbumArt(Context context, String path) { 21038a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber byte[] compressed = null; 2104702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2105702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 2106702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File f = new File(path); 2107702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ParcelFileDescriptor pfd = ParcelFileDescriptor.open(f, 2108702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ParcelFileDescriptor.MODE_READ_ONLY); 2109702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 21108a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber MediaScanner scanner = new MediaScanner(context); 21118a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber compressed = scanner.extractAlbumArt(pfd.getFileDescriptor()); 2112702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project pfd.close(); 2113702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2114d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // If no embedded art exists, look for a suitable image file in the 2115d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // same directory as the media file. 2116d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // We look for, in order of preference: 2117d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // 0 AlbumArt.jpg 2118d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // 1 AlbumArt*Large.jpg 2119d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // 2 Any other jpg image with 'albumart' anywhere in the name 2120d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // 3 Any other jpg image 2121d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // 4 any other png image 21228a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (compressed == null && path != null) { 2123702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int lastSlash = path.lastIndexOf('/'); 2124702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (lastSlash > 0) { 2125d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen 2126d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen String artPath = path.substring(0, lastSlash + 1); 2127d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen 2128d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen String bestmatch = null; 2129d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen synchronized (sFolderArtMap) { 2130d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen if (sFolderArtMap.containsKey(artPath)) { 2131d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = sFolderArtMap.get(artPath); 2132d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } else { 2133d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen File dir = new File(artPath); 2134d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen String [] entrynames = dir.list(); 2135d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen if (entrynames == null) { 2136d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen return null; 2137d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } 2138d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = null; 2139d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen int matchlevel = 1000; 2140d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen for (int i = entrynames.length - 1; i >=0; i--) { 2141d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen String entry = entrynames[i].toLowerCase(); 2142d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen if (entry.equals("albumart.jpg")) { 2143d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = entrynames[i]; 2144d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen break; 2145d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } else if (entry.startsWith("albumart") 2146d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen && entry.endsWith("large.jpg") 2147d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen && matchlevel > 1) { 2148d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = entrynames[i]; 2149d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen matchlevel = 1; 2150d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } else if (entry.contains("albumart") 2151d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen && entry.endsWith(".jpg") 2152d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen && matchlevel > 2) { 2153d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = entrynames[i]; 2154d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen matchlevel = 2; 2155d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } else if (entry.endsWith(".jpg") && matchlevel > 3) { 2156d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = entrynames[i]; 2157d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen matchlevel = 3; 2158d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } else if (entry.endsWith(".png") && matchlevel > 4) { 2159d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = entrynames[i]; 2160d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen matchlevel = 4; 2161d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } 2162d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } 2163d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // note that this may insert null if no album art was found 2164d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen sFolderArtMap.put(artPath, bestmatch); 2165d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } 2166d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } 2167d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen 2168d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen if (bestmatch != null) { 2169d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen File file = new File(artPath + bestmatch); 2170d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen if (file.exists()) { 2171d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen compressed = new byte[(int)file.length()]; 2172d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen FileInputStream stream = null; 2173d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen try { 2174d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen stream = new FileInputStream(file); 2175d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen stream.read(compressed); 2176d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } catch (IOException ex) { 2177d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen compressed = null; 2178d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } finally { 2179d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen if (stream != null) { 2180d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen stream.close(); 2181d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } 2182702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2183702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2184702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2185702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2186702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 21878a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } catch (IOException e) { 21888a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 2189702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 21908a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber return compressed; 21918a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 2192702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 21938a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // Return a URI to write the album art to and update the database as necessary. 21948a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber Uri getAlbumArtOutputUri(SQLiteDatabase db, long album_id, Uri albumart_uri) { 21958a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber Uri out = null; 21968a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // TODO: this could be done more efficiently with a call to db.replace(), which 21978a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // replaces or inserts as needed, making it unnecessary to query() first. 21988a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (albumart_uri != null) { 21998a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber Cursor c = query(albumart_uri, new String [] { "_data" }, 22008a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber null, null, null); 220171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (c.moveToFirst()) { 22028a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber String albumart_path = c.getString(0); 22038a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (ensureFileExists(albumart_path)) { 22048a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber out = albumart_uri; 2205702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 220671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } else { 220771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen albumart_uri = null; 2208702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 22098a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber c.close(); 221071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 221171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (albumart_uri == null){ 22128a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber ContentValues initialValues = new ContentValues(); 22138a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber initialValues.put("album_id", album_id); 22148a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber try { 22158a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber ContentValues values = ensureFile(false, initialValues, "", ALBUM_THUMB_FOLDER); 22168a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber long rowId = db.insert("album_art", "_data", values); 22178a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (rowId > 0) { 22188a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber out = ContentUris.withAppendedId(ALBUMART_URI, rowId); 2219702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 22208a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } catch (IllegalStateException ex) { 22218a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber Log.e(TAG, "error creating album thumb file"); 22228a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 22238a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 22248a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber return out; 22258a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 22268a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 22278a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // Write out the album art to the output URI, recompresses the given Bitmap 22288a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // if necessary, otherwise writes the compressed data. 22298a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber private void writeAlbumArt( 22308a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber boolean need_to_recompress, Uri out, byte[] compressed, Bitmap bm) { 22318a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber boolean success = false; 22328a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber try { 22338a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber OutputStream outstream = getContext().getContentResolver().openOutputStream(out); 22348a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 22358a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (!need_to_recompress) { 22368a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // No need to recompress here, just write out the original 22378a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // compressed data here. 22388a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber outstream.write(compressed); 22398a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber success = true; 22408a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } else { 22418a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber success = bm.compress(Bitmap.CompressFormat.JPEG, 75, outstream); 2242702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 22438a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 22448a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber outstream.close(); 22458a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } catch (FileNotFoundException ex) { 22468a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber Log.e(TAG, "error creating file", ex); 2247702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } catch (IOException ex) { 22488a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber Log.e(TAG, "error creating file", ex); 22498a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 22508a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (!success) { 22518a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // the thumbnail was not written successfully, delete the entry that refers to it 22528a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber getContext().getContentResolver().delete(out, null, null); 2253702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 22548a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 22558a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 225671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen private ParcelFileDescriptor getThumb(SQLiteDatabase db, String path, long album_id, 225771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen Uri albumart_uri) { 225871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen ThumbData d = new ThumbData(); 225971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen d.db = db; 226071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen d.path = path; 226171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen d.album_id = album_id; 226271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen d.albumart_uri = albumart_uri; 226371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen return makeThumbInternal(d); 226471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 226571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen 226671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen private ParcelFileDescriptor makeThumbInternal(ThumbData d) { 22678a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber byte[] compressed = getCompressedAlbumArt(getContext(), d.path); 2268702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 22698a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (compressed == null) { 227071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen return null; 22718a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 22728a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 22738a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber Bitmap bm = null; 22748a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber boolean need_to_recompress = true; 22758a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 22768a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber try { 22778a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // get the size of the bitmap 22788a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber BitmapFactory.Options opts = new BitmapFactory.Options(); 22798a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.inJustDecodeBounds = true; 22808a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.inSampleSize = 1; 22818a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber BitmapFactory.decodeByteArray(compressed, 0, compressed.length, opts); 22828a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 22838a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // request a reasonably sized output image 22848a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // TODO: don't hardcode the size 22858a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber while (opts.outHeight > 320 || opts.outWidth > 320) { 22868a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.outHeight /= 2; 22878a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.outWidth /= 2; 22888a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.inSampleSize *= 2; 22898a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 22908a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 22918a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (opts.inSampleSize == 1) { 22928a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // The original album art was of proper size, we won't have to 22938a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // recompress the bitmap later. 22948a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber need_to_recompress = false; 22958a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } else { 22968a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // get the image for real now 22978a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.inJustDecodeBounds = false; 22988a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.inPreferredConfig = Bitmap.Config.RGB_565; 22998a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber bm = BitmapFactory.decodeByteArray(compressed, 0, compressed.length, opts); 23008a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 23018a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (bm != null && bm.getConfig() == null) { 23028a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber bm = bm.copy(Bitmap.Config.RGB_565, false); 23038a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 23048a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 23058a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } catch (Exception e) { 23068a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 23078a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 23088a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (need_to_recompress && bm == null) { 230971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen return null; 23108a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 23118a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 231271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (d.albumart_uri == null) { 231371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // this one doesn't need to be saved (probably a song with an unknown album), 231471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // so stick it in a memory file and return that 231571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen try { 231671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen MemoryFile file = new MemoryFile("albumthumb", compressed.length); 231771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen file.writeBytes(compressed, 0, 0, compressed.length); 231871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen file.deactivate(); 231971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen return file.getParcelFileDescriptor(); 232071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } catch (IOException e) { 232171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 232271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } else { 232371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // this one needs to actually be saved on the sd card 232471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen Uri out = getAlbumArtOutputUri(d.db, d.album_id, d.albumart_uri); 23258a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 232671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (out != null) { 232771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen writeAlbumArt(need_to_recompress, out, compressed, bm); 232871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen getContext().getContentResolver().notifyChange(MEDIA_URI, null); 232971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen try { 233071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen return openFileHelper(out, "r"); 233171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } catch (FileNotFoundException ex) { 233271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 233371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 23348a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 233571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen return null; 2336702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2337702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2338702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 2339702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Look up the artist or album entry for the given name, creating that entry 2340702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * if it does not already exists. 2341702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param db The database 2342702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param table The table to store the key/name pair in. 2343702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param keyField The name of the key-column 2344702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param nameField The name of the name-column 2345702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param rawName The name that the calling app was trying to insert into the database 234659948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen * @param cacheName The string that will be inserted in to the cache 234759948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen * @param path The full path to the file being inserted in to the audio table 234859948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen * @param albumHash A hash to distinguish between different albums of the same name 2349a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen * @param artist The name of the artist, if known 2350702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param cache The cache to add this entry to 2351702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param srcuri The Uri that prompted the call to this method, used for determining whether this is 2352702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * the internal or external database 2353702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @return The row ID for this artist/album, or -1 if the provided name was invalid 2354702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 2355702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private long getKeyIdForName(SQLiteDatabase db, String table, String keyField, String nameField, 235659948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen String rawName, String cacheName, String path, int albumHash, 2357a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen String artist, HashMap<String, Long> cache, Uri srcuri) { 2358702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long rowId; 2359702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2360702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rawName == null || rawName.length() == 0) { 2361702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return -1; 2362702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2363702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String k = MediaStore.Audio.keyFor(rawName); 2364702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2365702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (k == null) { 2366702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return -1; 2367702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2368702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 236959948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen boolean isAlbum = table.equals("albums"); 237059948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen boolean isUnknown = MediaFile.UNKNOWN_STRING.equals(rawName); 237159948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen 237259948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // To distinguish same-named albums, we append a hash of the path. 237359948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // Ideally we would also take things like CDDB ID in to account, so 237459948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // we can group files from the same album that aren't in the same 237559948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // folder, but this is a quick and easy start that works immediately 237659948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // without requiring support from the mp3, mp4 and Ogg meta data 237759948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // readers, as long as the albums are in different folders. 2378a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen if (isAlbum) { 237959948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen k = k + albumHash; 2380a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen if (isUnknown) { 2381a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen k = k + artist; 2382a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen } 238359948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen } 238459948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen 2385702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String [] selargs = { k }; 2386702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Cursor c = db.query(table, null, keyField + "=?", selargs, null, null, null); 2387702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2388702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 2389702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (c.getCount()) { 2390702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case 0: { 2391702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // insert new entry into table 2392702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues otherValues = new ContentValues(); 2393702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project otherValues.put(keyField, k); 2394702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project otherValues.put(nameField, rawName); 2395702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert(table, "duration", otherValues); 239659948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen if (path != null && isAlbum && ! isUnknown) { 2397702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // We just inserted a new album. Now create an album art thumbnail for it. 2398a9c4e330dacb37cfffa9c00f7da83cafde4accefMarco Nelissen makeThumbAsync(db, path, rowId); 2399702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2400702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 2401702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String volume = srcuri.toString().substring(16, 24); // extract internal/external 2402702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Uri uri = Uri.parse("content://media/" + volume + "/audio/" + table + "/" + rowId); 2403702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 2404702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2405702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2406702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2407702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case 1: { 2408702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Use the existing entry 2409702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project c.moveToFirst(); 2410702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = c.getLong(0); 2411702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2412702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Determine whether the current rawName is better than what's 2413702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // currently stored in the table, and update the table if it is. 2414702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String currentFancyName = c.getString(2); 2415702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String bestName = makeBestName(rawName, currentFancyName); 2416702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!bestName.equals(currentFancyName)) { 2417702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // update the table with the new name 2418702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues newValues = new ContentValues(); 2419702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newValues.put(nameField, bestName); 2420702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.update(table, newValues, "rowid="+Integer.toString((int)rowId), null); 2421702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String volume = srcuri.toString().substring(16, 24); // extract internal/external 2422702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Uri uri = Uri.parse("content://media/" + volume + "/audio/" + table + "/" + rowId); 2423702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 2424702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2425702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2426702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2427702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project default: 2428702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // corrupt database 2429702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Log.e(TAG, "Multiple entries in table " + table + " for key " + k); 2430702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = -1; 2431702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2432702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2433702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 2434702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (c != null) c.close(); 2435702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2436702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 243759948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen if (cache != null && ! isUnknown) { 243859948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen cache.put(cacheName, rowId); 2439702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2440702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return rowId; 2441702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2442702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2443702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 2444702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Returns the best string to use for display, given two names. 2445702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Note that this function does not necessarily return either one 2446702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * of the provided names; it may decide to return a better alternative 2447702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * (for example, specifying the inputs "Police" and "Police, The" will 2448702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * return "The Police") 2449702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 2450702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * The basic assumptions are: 2451702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * - longer is better ("The police" is better than "Police") 2452702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * - prefix is better ("The Police" is better than "Police, The") 2453702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * - accents are better ("Motörhead" is better than "Motorhead") 2454702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 2455702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param one The first of the two names to consider 2456702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param two The last of the two names to consider 2457702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @return The actual name to use 2458702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 2459702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String makeBestName(String one, String two) { 2460702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String name; 2461702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2462702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Longer names are usually better. 2463702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (one.length() > two.length()) { 2464702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project name = one; 2465702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 2466702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Names with accents are usually better, and conveniently sort later 2467702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (one.toLowerCase().compareTo(two.toLowerCase()) > 0) { 2468702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project name = one; 2469702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 2470702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project name = two; 2471702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2472702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2473702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2474702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Prefixes are better than postfixes. 2475702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (name.endsWith(", the") || name.endsWith(",the") || 2476702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project name.endsWith(", an") || name.endsWith(",an") || 2477702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project name.endsWith(", a") || name.endsWith(",a")) { 2478702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String fix = name.substring(1 + name.lastIndexOf(',')); 2479702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project name = fix.trim() + " " + name.substring(0, name.lastIndexOf(',')); 2480702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2481702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2482702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // TODO: word-capitalize the resulting name 2483702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return name; 2484702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2485702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2486702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2487702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 2488702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Looks up the database based on the given URI. 2489702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 2490702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param uri The requested URI 2491702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @returns the database for the given URI 2492702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 2493702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private DatabaseHelper getDatabaseForUri(Uri uri) { 2494702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized (mDatabases) { 2495702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (uri.getPathSegments().size() > 1) { 2496702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return mDatabases.get(uri.getPathSegments().get(0)); 2497702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2498702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2499702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return null; 2500702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2501702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2502702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 2503702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Attach the database for a volume (internal or external). 2504702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Does nothing if the volume is already attached, otherwise 2505702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * checks the volume ID and sets up the corresponding database. 2506702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 2507702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param volume to attach, either {@link #INTERNAL_VOLUME} or {@link #EXTERNAL_VOLUME}. 2508702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @return the content URI of the attached volume. 2509702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 2510702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private Uri attachVolume(String volume) { 2511702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (Process.supportsProcesses() && Binder.getCallingPid() != Process.myPid()) { 2512702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new SecurityException( 2513702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Opening and closing databases not allowed."); 2514702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2515702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2516702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized (mDatabases) { 2517702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (mDatabases.get(volume) != null) { // Already attached 2518702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Uri.parse("content://media/" + volume); 2519702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2520702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2521702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DatabaseHelper db; 2522702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (INTERNAL_VOLUME.equals(volume)) { 2523702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db = new DatabaseHelper(getContext(), INTERNAL_DATABASE_NAME, true); 2524702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else if (EXTERNAL_VOLUME.equals(volume)) { 2525702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String path = Environment.getExternalStorageDirectory().getPath(); 2526702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int volumeID = FileUtils.getFatVolumeId(path); 2527702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (LOCAL_LOGV) Log.v(TAG, path + " volume ID: " + volumeID); 2528702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2529702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // generate database name based on volume ID 2530702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String dbName = "external-" + Integer.toHexString(volumeID) + ".db"; 2531702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db = new DatabaseHelper(getContext(), dbName, false); 2532702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 2533702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalArgumentException("There is no volume named " + volume); 2534702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2535702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2536702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mDatabases.put(volume, db); 2537702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2538702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!db.mInternal) { 2539702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // clean up stray album art files: delete every file not in the database 2540702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File[] files = new File( 2541702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Environment.getExternalStorageDirectory(), 2542702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ALBUM_THUMB_FOLDER).listFiles(); 2543702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project HashSet<String> fileSet = new HashSet(); 2544702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project for (int i = 0; files != null && i < files.length; i++) { 2545702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project fileSet.add(files[i].getPath()); 2546702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2547702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2548702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Cursor cursor = query(MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI, 2549702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project new String[] { MediaStore.Audio.Albums.ALBUM_ART }, null, null, null); 2550702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 2551702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project while (cursor != null && cursor.moveToNext()) { 2552702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project fileSet.remove(cursor.getString(0)); 2553702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2554702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 2555702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (cursor != null) cursor.close(); 2556702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2557702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2558702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Iterator<String> iterator = fileSet.iterator(); 2559702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project while (iterator.hasNext()) { 2560702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String filename = iterator.next(); 2561702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (LOCAL_LOGV) Log.v(TAG, "deleting obsolete album art " + filename); 2562702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project new File(filename).delete(); 2563702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2564702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2565702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2566702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2567702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (LOCAL_LOGV) Log.v(TAG, "Attached volume: " + volume); 2568702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Uri.parse("content://media/" + volume); 2569702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2570702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2571702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 2572702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Detach the database for a volume (must be external). 2573702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Does nothing if the volume is already detached, otherwise 2574702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * closes the database and sends a notification to listeners. 2575702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 2576702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param uri The content URI of the volume, as returned by {@link #attachVolume} 2577702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 2578702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private void detachVolume(Uri uri) { 2579702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (Process.supportsProcesses() && Binder.getCallingPid() != Process.myPid()) { 2580702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new SecurityException( 2581702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Opening and closing databases not allowed."); 2582702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2583702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2584702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String volume = uri.getPathSegments().get(0); 2585702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (INTERNAL_VOLUME.equals(volume)) { 2586702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException( 2587702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Deleting the internal volume is not allowed"); 2588702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else if (!EXTERNAL_VOLUME.equals(volume)) { 2589702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalArgumentException( 2590702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "There is no volume named " + volume); 2591702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2592702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2593702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized (mDatabases) { 2594702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DatabaseHelper database = mDatabases.get(volume); 2595702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (database == null) return; 2596702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2597702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 2598702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // touch the database file to show it is most recently used 2599702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File file = new File(database.getReadableDatabase().getPath()); 2600702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project file.setLastModified(System.currentTimeMillis()); 2601702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } catch (SQLException e) { 2602702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Log.e(TAG, "Can't touch database file", e); 2603702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2604702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2605702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mDatabases.remove(volume); 2606702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project database.close(); 2607702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2608702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2609702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 2610702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (LOCAL_LOGV) Log.v(TAG, "Detached volume: " + volume); 2611702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2612702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2613702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static String TAG = "MediaProvider"; 2614702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final boolean LOCAL_LOGV = true; 2615b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private static final int DATABASE_VERSION = 77; 2616702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final String INTERNAL_DATABASE_NAME = "internal.db"; 2617702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2618702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // maximum number of cached external databases to keep 2619702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int MAX_EXTERNAL_DATABASES = 3; 2620702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2621702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Delete databases that have not been used in two months 2622702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // 60 days in milliseconds (1000 * 60 * 60 * 24 * 60) 2623702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final long OBSOLETE_DATABASE_DB = 5184000000L; 2624702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2625702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private HashMap<String, DatabaseHelper> mDatabases; 2626702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2627702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private Worker mThumbWorker; 2628702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private Handler mThumbHandler; 2629702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2630702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // name of the volume currently being scanned by the media scanner (or null) 2631702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private String mMediaScannerVolume; 2632702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2633702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project static final String INTERNAL_VOLUME = "internal"; 2634702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project static final String EXTERNAL_VOLUME = "external"; 2635702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project static final String ALBUM_THUMB_FOLDER = "albumthumbs"; 2636702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2637702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // path for writing contents of in memory temp database 2638702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private String mTempDatabasePath; 2639702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2640702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int IMAGES_MEDIA = 1; 2641702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int IMAGES_MEDIA_ID = 2; 2642702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int IMAGES_THUMBNAILS = 3; 2643702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int IMAGES_THUMBNAILS_ID = 4; 2644702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2645702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_MEDIA = 100; 2646702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_MEDIA_ID = 101; 2647702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_MEDIA_ID_GENRES = 102; 2648702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_MEDIA_ID_GENRES_ID = 103; 2649702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_MEDIA_ID_PLAYLISTS = 104; 2650702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_MEDIA_ID_PLAYLISTS_ID = 105; 2651702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_GENRES = 106; 2652702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_GENRES_ID = 107; 2653702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_GENRES_ID_MEMBERS = 108; 2654702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_GENRES_ID_MEMBERS_ID = 109; 2655702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_PLAYLISTS = 110; 2656702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_PLAYLISTS_ID = 111; 2657702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_PLAYLISTS_ID_MEMBERS = 112; 2658702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_PLAYLISTS_ID_MEMBERS_ID = 113; 2659702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ARTISTS = 114; 2660702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ARTISTS_ID = 115; 2661702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ALBUMS = 116; 2662702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ALBUMS_ID = 117; 2663702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ARTISTS_ID_ALBUMS = 118; 2664702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ALBUMART = 119; 2665702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ALBUMART_ID = 120; 266671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen private static final int AUDIO_ALBUMART_FILE_ID = 121; 2667702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2668702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int VIDEO_MEDIA = 200; 2669702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int VIDEO_MEDIA_ID = 201; 2670b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private static final int VIDEO_THUMBNAILS = 202; 2671b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private static final int VIDEO_THUMBNAILS_ID = 203; 2672702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2673702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int VOLUMES = 300; 2674702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int VOLUMES_ID = 301; 2675702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2676a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen private static final int AUDIO_SEARCH_LEGACY = 400; 2677a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen private static final int AUDIO_SEARCH_BASIC = 401; 2678a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen private static final int AUDIO_SEARCH_FANCY = 402; 2679702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2680702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int MEDIA_SCANNER = 500; 2681702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2682702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final UriMatcher URI_MATCHER = 2683702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project new UriMatcher(UriMatcher.NO_MATCH); 2684702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2685b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private static final String[] ID_PROJECTION = new String[] { 2686b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen MediaStore.MediaColumns._ID 2687b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen }; 2688b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 2689702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final String[] MIME_TYPE_PROJECTION = new String[] { 2690702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.MediaColumns._ID, // 0 2691702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.MediaColumns.MIME_TYPE, // 1 2692702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project }; 2693702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2694b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private static final String[] READY_FLAG_PROJECTION = new String[] { 2695b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen MediaStore.MediaColumns._ID, 2696b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen MediaStore.MediaColumns.DATA, 2697b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen Images.Media.MINI_THUMB_MAGIC 2698b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen }; 2699b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 2700702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final String[] EXTERNAL_DATABASE_TABLES = new String[] { 2701702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "images", 2702702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "thumbnails", 2703702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_meta", 2704702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "artists", 2705702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "albums", 2706702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_genres", 2707702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_genres_map", 2708702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_playlists", 2709702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_playlists_map", 2710702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "video", 2711702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project }; 2712702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2713702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project static 2714702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project { 2715702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/images/media", IMAGES_MEDIA); 2716702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/images/media/#", IMAGES_MEDIA_ID); 2717702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/images/thumbnails", IMAGES_THUMBNAILS); 2718702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/images/thumbnails/#", IMAGES_THUMBNAILS_ID); 2719702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2720702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/media", AUDIO_MEDIA); 2721702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/media/#", AUDIO_MEDIA_ID); 2722702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/media/#/genres", AUDIO_MEDIA_ID_GENRES); 2723702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/media/#/genres/#", AUDIO_MEDIA_ID_GENRES_ID); 2724702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/media/#/playlists", AUDIO_MEDIA_ID_PLAYLISTS); 2725702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/media/#/playlists/#", AUDIO_MEDIA_ID_PLAYLISTS_ID); 2726702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/genres", AUDIO_GENRES); 2727702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/genres/#", AUDIO_GENRES_ID); 2728702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/genres/#/members", AUDIO_GENRES_ID_MEMBERS); 2729702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/genres/#/members/#", AUDIO_GENRES_ID_MEMBERS_ID); 2730702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/playlists", AUDIO_PLAYLISTS); 2731702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/playlists/#", AUDIO_PLAYLISTS_ID); 2732702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/playlists/#/members", AUDIO_PLAYLISTS_ID_MEMBERS); 2733702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/playlists/#/members/#", AUDIO_PLAYLISTS_ID_MEMBERS_ID); 2734702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/artists", AUDIO_ARTISTS); 2735702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/artists/#", AUDIO_ARTISTS_ID); 2736702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/artists/#/albums", AUDIO_ARTISTS_ID_ALBUMS); 2737702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/albums", AUDIO_ALBUMS); 2738702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/albums/#", AUDIO_ALBUMS_ID); 2739702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/albumart", AUDIO_ALBUMART); 2740702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/albumart/#", AUDIO_ALBUMART_ID); 274171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen URI_MATCHER.addURI("media", "*/audio/media/#/albumart", AUDIO_ALBUMART_FILE_ID); 2742702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2743702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/video/media", VIDEO_MEDIA); 2744702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/video/media/#", VIDEO_MEDIA_ID); 2745b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen URI_MATCHER.addURI("media", "*/video/thumbnails", VIDEO_THUMBNAILS); 2746b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen URI_MATCHER.addURI("media", "*/video/thumbnails/#", VIDEO_THUMBNAILS_ID); 2747702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2748702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/media_scanner", MEDIA_SCANNER); 2749702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2750702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*", VOLUMES_ID); 2751702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", null, VOLUMES); 2752702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2753a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen /** 2754a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen * @deprecated use the 'basic' or 'fancy' search Uris instead 2755a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen */ 2756702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/" + SearchManager.SUGGEST_URI_PATH_QUERY, 2757a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen AUDIO_SEARCH_LEGACY); 2758702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/" + SearchManager.SUGGEST_URI_PATH_QUERY + "/*", 2759a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen AUDIO_SEARCH_LEGACY); 2760a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen 2761a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // used for search suggestions 2762a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen URI_MATCHER.addURI("media", "*/audio/search/" + SearchManager.SUGGEST_URI_PATH_QUERY, 2763a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen AUDIO_SEARCH_BASIC); 2764a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen URI_MATCHER.addURI("media", "*/audio/search/" + SearchManager.SUGGEST_URI_PATH_QUERY + 2765a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "/*", AUDIO_SEARCH_BASIC); 2766a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen 2767a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // used by the music app's search activity 2768a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen URI_MATCHER.addURI("media", "*/audio/search/fancy", AUDIO_SEARCH_FANCY); 2769a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen URI_MATCHER.addURI("media", "*/audio/search/fancy/*", AUDIO_SEARCH_FANCY); 2770702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2771702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project} 2772