MediaProvider.java revision ea8ed74e997619531921fb4138728b7d65c35089
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.*; 210027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissenimport android.database.AbstractCursor; 22702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.database.Cursor; 23ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissenimport android.database.DatabaseUtils; 240027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissenimport android.database.MatrixCursor; 25702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.database.SQLException; 26702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.database.sqlite.SQLiteDatabase; 27702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.database.sqlite.SQLiteOpenHelper; 28702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.database.sqlite.SQLiteQueryBuilder; 29702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.graphics.Bitmap; 30702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.graphics.BitmapFactory; 31702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.media.MediaScanner; 32b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chenimport android.media.MiniThumbFile; 33702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.net.Uri; 34702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.Binder; 35702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.Environment; 36702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.FileUtils; 37702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.Handler; 38ab43e1853533e4d9352c251d53c36fb645077e43Chih-Chung Changimport android.os.HandlerThread; 39702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.Looper; 4071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissenimport android.os.MemoryFile; 41702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.Message; 42702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.ParcelFileDescriptor; 43702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.Process; 44702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.BaseColumns; 45702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.MediaStore; 46702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.MediaStore.Audio; 47702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.MediaStore.Images; 48702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.MediaStore.MediaColumns; 49702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.MediaStore.Video; 50702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.MediaStore.Images.ImageColumns; 51702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.text.TextUtils; 52702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.util.Log; 53702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 54702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.io.File; 55702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.io.FileInputStream; 56702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.io.FileNotFoundException; 57702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.io.IOException; 58702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.io.OutputStream; 59702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.text.Collator; 60cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissenimport java.util.ArrayList; 61702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.util.HashMap; 62702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.util.HashSet; 63702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.util.Iterator; 64f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissenimport java.util.List; 65b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chenimport java.util.PriorityQueue; 668a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huberimport java.util.Stack; 67702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 68702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project/** 69702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Media content provider. See {@link android.provider.MediaStore} for details. 70702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Separate databases are kept for each external storage card we see (using the 71702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * card's ID as an index). The content visible at content://media/external/... 72702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * changes with the card. 73702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 74702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectpublic class MediaProvider extends ContentProvider { 75702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final Uri MEDIA_URI = Uri.parse("content://media"); 76702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final Uri ALBUMART_URI = Uri.parse("content://media/external/audio/albumart"); 77b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private static final int ALBUM_THUMB = 1; 78b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private static final int IMAGE_THUMB = 2; 79702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 80702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final HashMap<String, String> sArtistAlbumsMap = new HashMap<String, String>(); 81d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen private static final HashMap<String, String> sFolderArtMap = new HashMap<String, String>(); 82702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 838a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // A HashSet of paths that are pending creation of album art thumbnails. 848a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber private HashSet mPendingThumbs = new HashSet(); 858a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 868a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // A Stack of outstanding thumbnail requests. 878a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber private Stack mThumbRequestStack = new Stack(); 888a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 8920434e032e498b716f87cce2f23dd646819218bfRay Chen // The lock of mMediaThumbQueue protects both mMediaThumbQueue and mCurrentThumbRequest. 9020434e032e498b716f87cce2f23dd646819218bfRay Chen private MediaThumbRequest mCurrentThumbRequest = null; 91b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private PriorityQueue<MediaThumbRequest> mMediaThumbQueue = 92b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen new PriorityQueue<MediaThumbRequest>(MediaThumbRequest.PRIORITY_NORMAL, 93b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen MediaThumbRequest.getComparator()); 94b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 95a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // For compatibility with the approximately 0 apps that used mediaprovider search in 96a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // releases 1.0, 1.1 or 1.5 97a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen private String[] mSearchColsLegacy = new String[] { 98a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen android.provider.BaseColumns._ID, 99a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen MediaStore.Audio.Media.MIME_TYPE, 100a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "(CASE WHEN grouporder=1 THEN " + R.drawable.ic_search_category_music_artist + 101a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen " ELSE CASE WHEN grouporder=2 THEN " + R.drawable.ic_search_category_music_album + 102a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen " ELSE " + R.drawable.ic_search_category_music_song + " END END" + 103a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen ") AS " + SearchManager.SUGGEST_COLUMN_ICON_1, 104a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "0 AS " + SearchManager.SUGGEST_COLUMN_ICON_2, 105a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "text1 AS " + SearchManager.SUGGEST_COLUMN_TEXT_1, 106a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "text1 AS " + SearchManager.SUGGEST_COLUMN_QUERY, 107a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "CASE when grouporder=1 THEN data1 ELSE artist END AS data1", 108a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "CASE when grouporder=1 THEN data2 ELSE " + 109a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "CASE WHEN grouporder=2 THEN NULL ELSE album END END AS data2", 110a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "match as ar", 111a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen SearchManager.SUGGEST_COLUMN_INTENT_DATA, 112a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "grouporder", 113ea74c8add2d5b4215dfeb69183632d9e9797ac5aMarco Nelissen "NULL AS itemorder" // We should be sorting by the artist/album/title keys, but that 114ea74c8add2d5b4215dfeb69183632d9e9797ac5aMarco Nelissen // column is not available here, and the list is already sorted. 115a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen }; 116a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen private String[] mSearchColsFancy = new String[] { 117a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen android.provider.BaseColumns._ID, 118a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen MediaStore.Audio.Media.MIME_TYPE, 119a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen MediaStore.Audio.Artists.ARTIST, 120a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen MediaStore.Audio.Albums.ALBUM, 121a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen MediaStore.Audio.Media.TITLE, 122a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "data1", 123a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "data2", 124a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen }; 12563f748ff8b258d9110038778a006b3000164fbeeSatish Sampath // If this array gets changed, please update the constant below to point to the correct item. 126a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen private String[] mSearchColsBasic = new String[] { 127a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen android.provider.BaseColumns._ID, 128a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen MediaStore.Audio.Media.MIME_TYPE, 129a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "(CASE WHEN grouporder=1 THEN " + R.drawable.ic_search_category_music_artist + 130a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen " ELSE CASE WHEN grouporder=2 THEN " + R.drawable.ic_search_category_music_album + 131a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen " ELSE " + R.drawable.ic_search_category_music_song + " END END" + 132a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen ") AS " + SearchManager.SUGGEST_COLUMN_ICON_1, 133a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "text1 AS " + SearchManager.SUGGEST_COLUMN_TEXT_1, 134a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "text1 AS " + SearchManager.SUGGEST_COLUMN_QUERY, 13563f748ff8b258d9110038778a006b3000164fbeeSatish Sampath "(CASE WHEN grouporder=1 THEN '%1'" + // %1 gets replaced with localized string. 13663f748ff8b258d9110038778a006b3000164fbeeSatish Sampath " ELSE CASE WHEN grouporder=3 THEN artist || ' - ' || album" + 137e31cfb1a2c21e7ac7a646d40afbb48f49fab6907Marco Nelissen " ELSE CASE WHEN text2!='" + MediaStore.UNKNOWN_STRING + "' THEN text2" + 13863f748ff8b258d9110038778a006b3000164fbeeSatish Sampath " ELSE NULL END END END) AS " + SearchManager.SUGGEST_COLUMN_TEXT_2, 139a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen SearchManager.SUGGEST_COLUMN_INTENT_DATA 140a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen }; 14163f748ff8b258d9110038778a006b3000164fbeeSatish Sampath // Position of the TEXT_2 item in the above array. 14263f748ff8b258d9110038778a006b3000164fbeeSatish Sampath private final int SEARCH_COLUMN_BASIC_TEXT2 = 5; 143a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen 144a9c4e330dacb37cfffa9c00f7da83cafde4accefMarco Nelissen private Uri mAlbumArtBaseUri = Uri.parse("content://media/external/audio/albumart"); 145a9c4e330dacb37cfffa9c00f7da83cafde4accefMarco Nelissen 146702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private BroadcastReceiver mUnmountReceiver = new BroadcastReceiver() { 147702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 148702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public void onReceive(Context context, Intent intent) { 149702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (intent.getAction().equals(Intent.ACTION_MEDIA_EJECT)) { 150702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Remove the external volume and then notify all cursors backed by 151702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // data on that volume 152702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project detachVolume(Uri.parse("content://media/external")); 153d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen sFolderArtMap.clear(); 154b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen MiniThumbFile.reset(); 155702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 156702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 157702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project }; 158702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 159702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 160702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Wrapper class for a specific database (associated with one particular 161702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * external card, or with internal storage). Can open the actual database 162702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * on demand, create and upgrade the schema, etc. 163702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 164702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final class DatabaseHelper extends SQLiteOpenHelper { 165702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final Context mContext; 166702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final boolean mInternal; // True if this is the internal database 167702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 168702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // In memory caches of artist and album data. 169702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project HashMap<String, Long> mArtistCache = new HashMap<String, Long>(); 170702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project HashMap<String, Long> mAlbumCache = new HashMap<String, Long>(); 171702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 172702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public DatabaseHelper(Context context, String name, boolean internal) { 173702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project super(context, name, null, DATABASE_VERSION); 174702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mContext = context; 175702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mInternal = internal; 176702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 177702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 178702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 179702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Creates database the first time we try to open it. 180702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 181702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 182702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public void onCreate(final SQLiteDatabase db) { 183702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project updateDatabase(db, mInternal, 0, DATABASE_VERSION); 184702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 185702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 186702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 187702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Updates the database format when a new content provider is used 188702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * with an older database format. 189702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 190702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 191702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public void onUpgrade(final SQLiteDatabase db, final int oldV, final int newV) { 192702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project updateDatabase(db, mInternal, oldV, newV); 193702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 194702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 195702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 196702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Touch this particular database and garbage collect old databases. 197702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * An LRU cache system is used to clean up databases for old external 198702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * storage volumes. 199702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 200702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 201702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public void onOpen(SQLiteDatabase db) { 202702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (mInternal) return; // The internal database is kept separately. 203702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 204702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // touch the database file to show it is most recently used 205702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File file = new File(db.getPath()); 206702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long now = System.currentTimeMillis(); 207702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project file.setLastModified(now); 208702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 209702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // delete least recently used databases if we are over the limit 210702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String[] databases = mContext.databaseList(); 211702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int count = databases.length; 212702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int limit = MAX_EXTERNAL_DATABASES; 213702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 214702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // delete external databases that have not been used in the past two months 215702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long twoMonthsAgo = now - OBSOLETE_DATABASE_DB; 216702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project for (int i = 0; i < databases.length; i++) { 217702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File other = mContext.getDatabasePath(databases[i]); 218702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (INTERNAL_DATABASE_NAME.equals(databases[i]) || file.equals(other)) { 219702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project databases[i] = null; 220702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count--; 221702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (file.equals(other)) { 222702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // reduce limit to account for the existence of the database we 223702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // are about to open, which we removed from the list. 224702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project limit--; 225702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 226702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 227702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long time = other.lastModified(); 228702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (time < twoMonthsAgo) { 229702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (LOCAL_LOGV) Log.v(TAG, "Deleting old database " + databases[i]); 230702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mContext.deleteDatabase(databases[i]); 231702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project databases[i] = null; 232702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count--; 233702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 234702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 235702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 236702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 237702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // delete least recently used databases until 238702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // we are no longer over the limit 239702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project while (count > limit) { 240702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int lruIndex = -1; 241702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long lruTime = 0; 242702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 243702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project for (int i = 0; i < databases.length; i++) { 244702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (databases[i] != null) { 245702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long time = mContext.getDatabasePath(databases[i]).lastModified(); 246702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (lruTime == 0 || time < lruTime) { 247702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project lruIndex = i; 248702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project lruTime = time; 249702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 250702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 251702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 252702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 253702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // delete least recently used database 254702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (lruIndex != -1) { 255702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (LOCAL_LOGV) Log.v(TAG, "Deleting old database " + databases[lruIndex]); 256702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mContext.deleteDatabase(databases[lruIndex]); 257702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project databases[lruIndex] = null; 258702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count--; 259702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 260702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 261702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 262702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 263702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 264702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 265702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public boolean onCreate() { 266acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen sArtistAlbumsMap.put(MediaStore.Audio.Albums._ID, "audio.album_id AS " + 267acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen MediaStore.Audio.Albums._ID); 268702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Albums.ALBUM, "album"); 269702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Albums.ALBUM_KEY, "album_key"); 270acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen sArtistAlbumsMap.put(MediaStore.Audio.Albums.FIRST_YEAR, "MIN(year) AS " + 271702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.Audio.Albums.FIRST_YEAR); 272acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen sArtistAlbumsMap.put(MediaStore.Audio.Albums.LAST_YEAR, "MAX(year) AS " + 273702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.Audio.Albums.LAST_YEAR); 274702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Media.ARTIST, "artist"); 275702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Media.ARTIST_ID, "artist"); 276702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Media.ARTIST_KEY, "artist_key"); 277acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen sArtistAlbumsMap.put(MediaStore.Audio.Albums.NUMBER_OF_SONGS, "count(*) AS " + 278acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen MediaStore.Audio.Albums.NUMBER_OF_SONGS); 279acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen sArtistAlbumsMap.put(MediaStore.Audio.Albums.ALBUM_ART, "album_art._data AS " + 280acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen MediaStore.Audio.Albums.ALBUM_ART); 281702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 28263f748ff8b258d9110038778a006b3000164fbeeSatish Sampath mSearchColsBasic[SEARCH_COLUMN_BASIC_TEXT2] = 28363f748ff8b258d9110038778a006b3000164fbeeSatish Sampath mSearchColsBasic[SEARCH_COLUMN_BASIC_TEXT2].replaceAll( 28463f748ff8b258d9110038778a006b3000164fbeeSatish Sampath "%1", getContext().getString(R.string.artist_label)); 285702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mDatabases = new HashMap<String, DatabaseHelper>(); 286702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project attachVolume(INTERNAL_VOLUME); 287702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 288702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project IntentFilter iFilter = new IntentFilter(Intent.ACTION_MEDIA_EJECT); 289702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project iFilter.addDataScheme("file"); 290702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().registerReceiver(mUnmountReceiver, iFilter); 291702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 292702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // open external database if external storage is mounted 293702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String state = Environment.getExternalStorageState(); 294702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (Environment.MEDIA_MOUNTED.equals(state) || 295702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) { 296702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project attachVolume(EXTERNAL_VOLUME); 297702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 298702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 299ab43e1853533e4d9352c251d53c36fb645077e43Chih-Chung Chang HandlerThread ht = new HandlerThread("thumbs thread", Process.THREAD_PRIORITY_BACKGROUND); 300ab43e1853533e4d9352c251d53c36fb645077e43Chih-Chung Chang ht.start(); 301ab43e1853533e4d9352c251d53c36fb645077e43Chih-Chung Chang mThumbHandler = new Handler(ht.getLooper()) { 302702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 303702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public void handleMessage(Message msg) { 304b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (msg.what == IMAGE_THUMB) { 305b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen synchronized (mMediaThumbQueue) { 30620434e032e498b716f87cce2f23dd646819218bfRay Chen mCurrentThumbRequest = mMediaThumbQueue.poll(); 307b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 30820434e032e498b716f87cce2f23dd646819218bfRay Chen if (mCurrentThumbRequest == null) { 309b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen Log.w(TAG, "Have message but no request?"); 310b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } else { 311b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen try { 31220434e032e498b716f87cce2f23dd646819218bfRay Chen File origFile = new File(mCurrentThumbRequest.mPath); 3134d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen if (origFile.exists() && origFile.length() > 0) { 31420434e032e498b716f87cce2f23dd646819218bfRay Chen mCurrentThumbRequest.execute(); 3154d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen } else { 3164d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen // original file hasn't been stored yet 3174d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen synchronized (mMediaThumbQueue) { 31820434e032e498b716f87cce2f23dd646819218bfRay Chen Log.w(TAG, "original file hasn't been stored yet: " + mCurrentThumbRequest.mPath); 3194d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen } 3204d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen } 321b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } catch (IOException ex) { 3221d6eba9e1e28c722aa73a651d86a2efe2b937bf2Ray Chen Log.w(TAG, ex); 3231d6eba9e1e28c722aa73a651d86a2efe2b937bf2Ray Chen } catch (UnsupportedOperationException ex) { 3241d6eba9e1e28c722aa73a651d86a2efe2b937bf2Ray Chen // This could happen if we unplug the sd card during insert/update/delete 3251d6eba9e1e28c722aa73a651d86a2efe2b937bf2Ray Chen // See getDatabaseForUri. 3261d6eba9e1e28c722aa73a651d86a2efe2b937bf2Ray Chen Log.w(TAG, ex); 327b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } finally { 32820434e032e498b716f87cce2f23dd646819218bfRay Chen synchronized (mCurrentThumbRequest) { 32920434e032e498b716f87cce2f23dd646819218bfRay Chen mCurrentThumbRequest.mState = MediaThumbRequest.State.DONE; 33020434e032e498b716f87cce2f23dd646819218bfRay Chen mCurrentThumbRequest.notifyAll(); 331b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 332b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 333b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 334b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } else if (msg.what == ALBUM_THUMB) { 335b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen ThumbData d; 336b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen synchronized (mThumbRequestStack) { 337b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen d = (ThumbData)mThumbRequestStack.pop(); 338b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 3398a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 340b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen makeThumbInternal(d); 341b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen synchronized (mPendingThumbs) { 342b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen mPendingThumbs.remove(d.path); 343b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 3448a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 345702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 346702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project }; 347702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 348702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return true; 349702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 350702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 351702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 352702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * This method takes care of updating all the tables in the database to the 353702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * current version, creating them if necessary. 354702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * This method can only update databases at schema 63 or higher, which was 355702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * created August 1, 2008. Older database will be cleared and recreated. 356702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param db Database 357702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param internal True if this is the internal media database 358702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 359702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static void updateDatabase(SQLiteDatabase db, boolean internal, 360702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int fromVersion, int toVersion) { 361702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 362702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // sanity checks 363702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (toVersion != DATABASE_VERSION) { 364702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Log.e(TAG, "Illegal update request. Got " + toVersion + ", expected " + 365702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DATABASE_VERSION); 366702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalArgumentException(); 367702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else if (fromVersion > toVersion) { 36895ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen Log.e(TAG, "Illegal update request: can't downgrade from " + fromVersion + 369702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " to " + toVersion + ". Did you forget to wipe data?"); 370702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalArgumentException(); 371702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 372702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 373acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // Revisions 84-86 were a failed attempt at supporting the "album artist" id3 tag 374acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // We can't downgrade from those revisions, so start over. 375022eb71bfe8ec65b8817eaa432a530194210ec23Marco Nelissen // (the initial change to do this was wrong, so now we actually need to start over 376022eb71bfe8ec65b8817eaa432a530194210ec23Marco Nelissen // if the database version is 84-89) 377022eb71bfe8ec65b8817eaa432a530194210ec23Marco Nelissen if (fromVersion < 63 || (fromVersion >= 84 && fromVersion <= 89)) { 378acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen fromVersion = 63; 379702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Drop everything and start over. 380702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Log.i(TAG, "Upgrading media database from version " + 381702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project fromVersion + " to " + toVersion + ", which will destroy all old data"); 382702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS images"); 383702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS images_cleanup"); 384702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS thumbnails"); 385702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS thumbnails_cleanup"); 386702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS audio_meta"); 387702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS artists"); 388702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS albums"); 389702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS album_art"); 390702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP VIEW IF EXISTS artist_info"); 391702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP VIEW IF EXISTS album_info"); 392702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP VIEW IF EXISTS artists_albums_map"); 393702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS audio_meta_cleanup"); 394702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS audio_genres"); 395702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS audio_genres_map"); 396702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS audio_genres_cleanup"); 397702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS audio_playlists"); 398702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS audio_playlists_map"); 399702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS audio_playlists_cleanup"); 400702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS albumart_cleanup1"); 401702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS albumart_cleanup2"); 402702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS video"); 403702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS video_cleanup"); 404702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 405702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS images (" + 406702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 407702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_data TEXT," + 408702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_size INTEGER," + 409702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_display_name TEXT," + 410702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "mime_type TEXT," + 411702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "title TEXT," + 412702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_added INTEGER," + 413702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_modified INTEGER," + 414702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "description TEXT," + 415702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "picasa_id TEXT," + 416702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "isprivate INTEGER," + 417702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "latitude DOUBLE," + 418702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "longitude DOUBLE," + 419702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "datetaken INTEGER," + 420702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "orientation INTEGER," + 421702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "mini_thumb_magic INTEGER," + 422702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "bucket_id TEXT," + 423702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "bucket_display_name TEXT" + 424702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 425702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 426702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE INDEX IF NOT EXISTS mini_thumb_magic_index on images(mini_thumb_magic);"); 427702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 428702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS images_cleanup DELETE ON images " + 429702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 430702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE FROM thumbnails WHERE image_id = old._id;" + 431702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT _DELETE_FILE(old._data);" + 432702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 433702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 434b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // create image thumbnail table 435702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS thumbnails (" + 436702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 437702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_data TEXT," + 438702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "image_id INTEGER," + 439702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "kind INTEGER," + 440702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "width INTEGER," + 441702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "height INTEGER" + 442702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 443702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 444702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE INDEX IF NOT EXISTS image_id_index on thumbnails(image_id);"); 445702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 446702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS thumbnails_cleanup DELETE ON thumbnails " + 447702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 448702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT _DELETE_FILE(old._data);" + 449702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 450702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 451702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains meta data about audio files 452702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS audio_meta (" + 453702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 454216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen "_data TEXT UNIQUE NOT NULL," + 455702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_display_name TEXT," + 456702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_size INTEGER," + 457702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "mime_type TEXT," + 458702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_added INTEGER," + 459702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_modified INTEGER," + 460702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "title TEXT NOT NULL," + 461702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "title_key TEXT NOT NULL," + 462702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "duration INTEGER," + 463702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "artist_id INTEGER," + 464702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "composer TEXT," + 465702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "album_id INTEGER," + 466702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "track INTEGER," + // track is an integer to allow proper sorting 467702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "year INTEGER CHECK(year!=0)," + 468702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "is_ringtone INTEGER," + 469702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "is_music INTEGER," + 470702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "is_alarm INTEGER," + 471702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "is_notification INTEGER" + 472702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 473702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 474702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains a sort/group "key" and the preferred display name for artists 475702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS artists (" + 476702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "artist_id INTEGER PRIMARY KEY," + 477702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "artist_key TEXT NOT NULL UNIQUE," + 478702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "artist TEXT NOT NULL" + 479702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 480702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 481702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains a sort/group "key" and the preferred display name for albums 482702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS albums (" + 483702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "album_id INTEGER PRIMARY KEY," + 484702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "album_key TEXT NOT NULL UNIQUE," + 485702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "album TEXT NOT NULL" + 486702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 487702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 488702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS album_art (" + 489702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "album_id INTEGER PRIMARY KEY," + 490702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_data TEXT" + 491702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 492702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 493702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project recreateAudioView(db); 49495ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen 495702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 496702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Provides some extra info about artists, like the number of tracks 497702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // and albums for this artist 498702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE VIEW IF NOT EXISTS artist_info AS " + 499702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT artist_id AS _id, artist, artist_key, " + 500acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen "COUNT(DISTINCT album) AS number_of_albums, " + 501702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "COUNT(*) AS number_of_tracks FROM audio WHERE is_music=1 "+ 502702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "GROUP BY artist_key;"); 503702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 504702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Provides extra info albums, such as the number of tracks 505702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE VIEW IF NOT EXISTS album_info AS " + 506702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT audio.album_id AS _id, album, album_key, " + 507702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "MIN(year) AS minyear, " + 508702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "MAX(year) AS maxyear, artist, artist_id, artist_key, " + 509702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "count(*) AS " + MediaStore.Audio.Albums.NUMBER_OF_SONGS + 510702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ",album_art._data AS album_art" + 511702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " FROM audio LEFT OUTER JOIN album_art ON audio.album_id=album_art.album_id" + 512702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " WHERE is_music=1 GROUP BY audio.album_id;"); 513702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 514acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // For a given artist_id, provides the album_id for albums on 515acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // which the artist appears. 516acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("CREATE VIEW IF NOT EXISTS artists_albums_map AS " + 517acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen "SELECT DISTINCT artist_id, album_id FROM audio_meta;"); 518acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen 519702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /* 520702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Only external media volumes can handle genres, playlists, etc. 521702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 522702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!internal) { 523702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Cleans up when an audio file is deleted 524702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS audio_meta_cleanup DELETE ON audio_meta " + 525702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 526702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE FROM audio_genres_map WHERE audio_id = old._id;" + 527702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE FROM audio_playlists_map WHERE audio_id = old._id;" + 528702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 529702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 530702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains audio genre definitions 531702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS audio_genres (" + 532702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 533702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "name TEXT NOT NULL" + 534702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 535702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 536702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contiains mappings between audio genres and audio files 537702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS audio_genres_map (" + 538702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 539702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_id INTEGER NOT NULL," + 540702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "genre_id INTEGER NOT NULL" + 541702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 542702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 543702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Cleans up when an audio genre is delete 544702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS audio_genres_cleanup DELETE ON audio_genres " + 545702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 546702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE FROM audio_genres_map WHERE genre_id = old._id;" + 547702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 548702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 549702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains audio playlist definitions 550702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS audio_playlists (" + 551702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 552702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_data TEXT," + // _data is path for file based playlists, or null 553702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "name TEXT NOT NULL," + 554702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_added INTEGER," + 555702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_modified INTEGER" + 556702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 557702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 558702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains mappings between audio playlists and audio files 559702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS audio_playlists_map (" + 560702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 561702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_id INTEGER NOT NULL," + 562702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "playlist_id INTEGER NOT NULL," + 563702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "play_order INTEGER NOT NULL" + 564702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 565702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 566702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Cleans up when an audio playlist is deleted 567702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS audio_playlists_cleanup DELETE ON audio_playlists " + 568702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 569702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE FROM audio_playlists_map WHERE playlist_id = old._id;" + 570702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT _DELETE_FILE(old._data);" + 571702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 572702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 573702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Cleans up album_art table entry when an album is deleted 574702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS albumart_cleanup1 DELETE ON albums " + 575702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 576702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE FROM album_art WHERE album_id = old.album_id;" + 577702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 578702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 579702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Cleans up album_art when an album is deleted 580702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS albumart_cleanup2 DELETE ON album_art " + 581702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 582702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT _DELETE_FILE(old._data);" + 583702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 584702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 585702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 586702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains meta data about video files 587702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS video (" + 588702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 589702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_data TEXT NOT NULL," + 590702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_display_name TEXT," + 591702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_size INTEGER," + 592702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "mime_type TEXT," + 593702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_added INTEGER," + 594702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_modified INTEGER," + 595702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "title TEXT," + 596702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "duration INTEGER," + 597702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "artist TEXT," + 598702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "album TEXT," + 599702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "resolution TEXT," + 600702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "description TEXT," + 601702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "isprivate INTEGER," + // for YouTube videos 602702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "tags TEXT," + // for YouTube videos 603702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "category TEXT," + // for YouTube videos 604702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "language TEXT," + // for YouTube videos 605702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "mini_thumb_data TEXT," + 606702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "latitude DOUBLE," + 607702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "longitude DOUBLE," + 608702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "datetaken INTEGER," + 609702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "mini_thumb_magic INTEGER" + 610702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 611702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 612702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS video_cleanup DELETE ON video " + 613702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 614702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT _DELETE_FILE(old._data);" + 615702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 616702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 617702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 618702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // At this point the database is at least at schema version 63 (it was 619702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // either created at version 63 by the code above, or was already at 620702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // version 63 or later) 621702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 622702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 64) { 623702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // create the index that updates the database to schema version 64 624702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE INDEX IF NOT EXISTS sort_index on images(datetaken ASC, _id ASC);"); 625702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 626702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 627acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen /* 628acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen * Android 1.0 shipped with database version 64 629acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen */ 630acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen 631702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 65) { 632702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // create the index that updates the database to schema version 65 633702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE INDEX IF NOT EXISTS titlekey_index on audio_meta(title_key);"); 634702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 635702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 636403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen // In version 66, originally we updateBucketNames(db, "images"), 637403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen // but we need to do it in version 89 and therefore save the update here. 638702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 639702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 67) { 640702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // create the indices that update the database to schema version 67 641702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE INDEX IF NOT EXISTS albumkey_index on albums(album_key);"); 642702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE INDEX IF NOT EXISTS artistkey_index on artists(artist_key);"); 643702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 644702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 645702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 68) { 646702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Create bucket_id and bucket_display_name columns for the video table. 647702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("ALTER TABLE video ADD COLUMN bucket_id TEXT;"); 648702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("ALTER TABLE video ADD COLUMN bucket_display_name TEXT"); 649403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen 650403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen // In version 68, originally we updateBucketNames(db, "video"), 651403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen // but we need to do it in version 89 and therefore save the update here. 652702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 653702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 654702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 69) { 655702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project updateDisplayName(db, "images"); 656702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 657702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 658702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 70) { 659702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Create bookmark column for the video table. 660702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("ALTER TABLE video ADD COLUMN bookmark INTEGER;"); 661702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 66295ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen 663702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 71) { 664702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // There is no change to the database schema, however a code change 665702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // fixed parsing of metadata for certain files bought from the 666702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // iTunes music store, so we want to rescan files that might need it. 667702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // We do this by clearing the modification date in the database for 668702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // those files, so that the media scanner will see them as updated 669702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // and rescan them. 670702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("UPDATE audio_meta SET date_modified=0 WHERE _id IN (" + 671702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT _id FROM audio where mime_type='audio/mp4' AND " + 672e31cfb1a2c21e7ac7a646d40afbb48f49fab6907Marco Nelissen "artist='" + MediaStore.UNKNOWN_STRING + "' AND " + 673e31cfb1a2c21e7ac7a646d40afbb48f49fab6907Marco Nelissen "album='" + MediaStore.UNKNOWN_STRING + "'" + 674702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 675702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 67695ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen 677702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 72) { 678702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Create is_podcast and bookmark columns for the audio table. 679702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("ALTER TABLE audio_meta ADD COLUMN is_podcast INTEGER;"); 680702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("UPDATE audio_meta SET is_podcast=1 WHERE _data LIKE '%/podcasts/%';"); 681702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("UPDATE audio_meta SET is_music=0 WHERE is_podcast=1" + 682702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " AND _data NOT LIKE '%/music/%';"); 683702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("ALTER TABLE audio_meta ADD COLUMN bookmark INTEGER;"); 684702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 685702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // New columns added to tables aren't visible in views on those tables 686702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // without opening and closing the database (or using the 'vacuum' command, 687702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // which we can't do here because all this code runs inside a transaction). 688702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // To work around this, we drop and recreate the affected view and trigger. 689702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project recreateAudioView(db); 690702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 69195ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen 692acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen /* 693acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen * Android 1.5 shipped with database version 72 694acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen */ 695acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen 6968d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen if (fromVersion < 73) { 6978d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen // There is no change to the database schema, but we now do case insensitive 6988d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen // matching of folder names when determining whether something is music, a 6998d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen // ringtone, podcast, etc, so we might need to reclassify some files. 7008d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen db.execSQL("UPDATE audio_meta SET is_music=1 WHERE is_music=0 AND " + 7018d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen "_data LIKE '%/music/%';"); 7028d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen db.execSQL("UPDATE audio_meta SET is_ringtone=1 WHERE is_ringtone=0 AND " + 7038d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen "_data LIKE '%/ringtones/%';"); 7048d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen db.execSQL("UPDATE audio_meta SET is_notification=1 WHERE is_notification=0 AND " + 7058d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen "_data LIKE '%/notifications/%';"); 7068d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen db.execSQL("UPDATE audio_meta SET is_alarm=1 WHERE is_alarm=0 AND " + 7078d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen "_data LIKE '%/alarms/%';"); 7088d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen db.execSQL("UPDATE audio_meta SET is_podcast=1 WHERE is_podcast=0 AND " + 7098d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen "_data LIKE '%/podcasts/%';"); 7108d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen } 711a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen 712a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen if (fromVersion < 74) { 713a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // This view is used instead of the audio view by the union below, to force 714a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // sqlite to use the title_key index. This greatly reduces memory usage 715a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // (no separate copy pass needed for sorting, which could cause errors on 716a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // large datasets) and improves speed (by about 35% on a large dataset) 717a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen db.execSQL("CREATE VIEW IF NOT EXISTS searchhelpertitle AS SELECT * FROM audio " + 718a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "ORDER BY title_key;"); 719a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen 720a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen db.execSQL("CREATE VIEW IF NOT EXISTS search AS " + 721a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "SELECT _id," + 722a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "'artist' AS mime_type," + 723a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist," + 724a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS album," + 725a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS title," + 726a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist AS text1," + 727a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS text2," + 728a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "number_of_albums AS data1," + 729a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "number_of_tracks AS data2," + 730a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist_key AS match," + 731a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "'content://media/external/audio/artists/'||_id AS suggest_intent_data," + 732a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "1 AS grouporder " + 733e31cfb1a2c21e7ac7a646d40afbb48f49fab6907Marco Nelissen "FROM artist_info WHERE (artist!='" + MediaStore.UNKNOWN_STRING + "') " + 734a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "UNION ALL " + 735a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "SELECT _id," + 736a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "'album' AS mime_type," + 737a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist," + 738a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "album," + 739a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS title," + 740a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "album AS text1," + 741a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist AS text2," + 742a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS data1," + 743a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS data2," + 744a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist_key||' '||album_key AS match," + 745a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "'content://media/external/audio/albums/'||_id AS suggest_intent_data," + 746a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "2 AS grouporder " + 747e31cfb1a2c21e7ac7a646d40afbb48f49fab6907Marco Nelissen "FROM album_info WHERE (album!='" + MediaStore.UNKNOWN_STRING + "') " + 748a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "UNION ALL " + 749a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "SELECT searchhelpertitle._id AS _id," + 750a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "mime_type," + 751a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist," + 752a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "album," + 753a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "title," + 754a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "title AS text1," + 755a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist AS text2," + 756a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS data1," + 757a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS data2," + 758a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist_key||' '||album_key||' '||title_key AS match," + 759a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "'content://media/external/audio/media/'||searchhelpertitle._id AS " + 760a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "suggest_intent_data," + 761a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "3 AS grouporder " + 762a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "FROM searchhelpertitle WHERE (title != '') " 763a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen ); 764a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen } 76559948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen 76659948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen if (fromVersion < 75) { 76795ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen // Force a rescan of the audio entries so we can apply the new logic to 76859948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // distinguish same-named albums. 76959948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen db.execSQL("UPDATE audio_meta SET date_modified=0;"); 77059948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen db.execSQL("DELETE FROM albums"); 77159948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen } 77215d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen 77315d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen if (fromVersion < 76) { 77415d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen // We now ignore double quotes when building the key, so we have to remove all of them 77515d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen // from existing keys. 77615d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen db.execSQL("UPDATE audio_meta SET title_key=" + 77715d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen "REPLACE(title_key,x'081D08C29F081D',x'081D') " + 77815d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen "WHERE title_key LIKE '%'||x'081D08C29F081D'||'%';"); 77915d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen db.execSQL("UPDATE albums SET album_key=" + 78015d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen "REPLACE(album_key,x'081D08C29F081D',x'081D') " + 78115d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen "WHERE album_key LIKE '%'||x'081D08C29F081D'||'%';"); 78215d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen db.execSQL("UPDATE artists SET artist_key=" + 78315d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen "REPLACE(artist_key,x'081D08C29F081D',x'081D') " + 78415d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen "WHERE artist_key LIKE '%'||x'081D08C29F081D'||'%';"); 78515d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen } 786b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 787acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen /* 788acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen * Android 1.6 shipped with database version 76 789acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen */ 790acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen 791b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (fromVersion < 77) { 792b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // create video thumbnail table 793b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen db.execSQL("CREATE TABLE IF NOT EXISTS videothumbnails (" + 794b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "_id INTEGER PRIMARY KEY," + 795b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "_data TEXT," + 796b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "video_id INTEGER," + 797b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "kind INTEGER," + 798b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "width INTEGER," + 799b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "height INTEGER" + 800b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen ");"); 801b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 802b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen db.execSQL("CREATE INDEX IF NOT EXISTS video_id_index on videothumbnails(video_id);"); 803b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 804b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen db.execSQL("CREATE TRIGGER IF NOT EXISTS videothumbnails_cleanup DELETE ON videothumbnails " + 805b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "BEGIN " + 806b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "SELECT _DELETE_FILE(old._data);" + 807b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "END"); 808b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 8091769168ade7b67f8695a4e4f3c69625aca0811d5Ray Chen 810acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen /* 811acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen * Android 2.0 and 2.0.1 shipped with database version 77 812acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen */ 813acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen 8141769168ade7b67f8695a4e4f3c69625aca0811d5Ray Chen if (fromVersion < 78) { 815044b029d9023f55e8e8861ed2f6e192f1b34f9bbRay Chen // Force a rescan of the video entries so we can update 8161769168ade7b67f8695a4e4f3c69625aca0811d5Ray Chen // latest changed DATE_TAKEN units (in milliseconds). 8171769168ade7b67f8695a4e4f3c69625aca0811d5Ray Chen db.execSQL("UPDATE video SET date_modified=0;"); 8181769168ade7b67f8695a4e4f3c69625aca0811d5Ray Chen } 819268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen 820acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen /* 821acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen * Android 2.1 shipped with database version 78 822acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen */ 823acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen 824268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen if (fromVersion < 79) { 825268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen // move /sdcard/albumthumbs to 826268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen // /sdcard/Android/data/com.android.providers.media/albumthumbs, 827268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen // and update the database accordingly 828268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen 829268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen String storageroot = Environment.getExternalStorageDirectory().getAbsolutePath(); 830268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen String oldthumbspath = storageroot + "/albumthumbs"; 831268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen String newthumbspath = storageroot + "/" + ALBUM_THUMB_FOLDER; 832268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen File thumbsfolder = new File(oldthumbspath); 833268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen if (thumbsfolder.exists()) { 834268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen // move folder to its new location 835268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen File newthumbsfolder = new File(newthumbspath); 836268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen newthumbsfolder.getParentFile().mkdirs(); 837268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen if(thumbsfolder.renameTo(newthumbsfolder)) { 838268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen // update the database 839268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen db.execSQL("UPDATE album_art SET _data=REPLACE(_data, '" + 840268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen oldthumbspath + "','" + newthumbspath + "');"); 841268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen } 842268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen } 843268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen } 844044b029d9023f55e8e8861ed2f6e192f1b34f9bbRay Chen 845044b029d9023f55e8e8861ed2f6e192f1b34f9bbRay Chen if (fromVersion < 80) { 846044b029d9023f55e8e8861ed2f6e192f1b34f9bbRay Chen // Force rescan of image entries to update DATE_TAKEN as UTC timestamp. 847044b029d9023f55e8e8861ed2f6e192f1b34f9bbRay Chen db.execSQL("UPDATE images SET date_modified=0;"); 848044b029d9023f55e8e8861ed2f6e192f1b34f9bbRay Chen } 8490ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen 850166a4e3cc66a645cc5e11d2f06d059512def0aceMarco Nelissen if (fromVersion < 81 && !internal) { 8510ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // Delete entries starting with /mnt/sdcard. This is for the benefit 8520ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // of users running builds between 2.0.1 and 2.1 final only, since 8530ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // users updating from 2.0 or earlier will not have such entries. 8540ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen 8550ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // First we need to update the _data fields in the affected tables, since 8560ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // otherwise deleting the entries will also delete the underlying files 8570ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // (via a trigger), and we want to keep them. 8580ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE audio_playlists SET _data='////' WHERE _data LIKE '/mnt/sdcard/%';"); 8590ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE images SET _data='////' WHERE _data LIKE '/mnt/sdcard/%';"); 8600ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE video SET _data='////' WHERE _data LIKE '/mnt/sdcard/%';"); 8610ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE videothumbnails SET _data='////' WHERE _data LIKE '/mnt/sdcard/%';"); 8620ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE thumbnails SET _data='////' WHERE _data LIKE '/mnt/sdcard/%';"); 8630ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE album_art SET _data='////' WHERE _data LIKE '/mnt/sdcard/%';"); 864216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen db.execSQL("UPDATE audio_meta SET _data='////' WHERE _data LIKE '/mnt/sdcard/%';"); 8650ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // Once the paths have been renamed, we can safely delete the entries 8660ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE FROM audio_playlists WHERE _data IS '////';"); 8670ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE FROM images WHERE _data IS '////';"); 8680ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE FROM video WHERE _data IS '////';"); 8690ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE FROM videothumbnails WHERE _data IS '////';"); 8700ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE FROM thumbnails WHERE _data IS '////';"); 8710ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE FROM audio_meta WHERE _data IS '////';"); 8720ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE FROM album_art WHERE _data IS '////';"); 8730ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen 8740ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // rename existing entries starting with /sdcard to /mnt/sdcard 8750ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE audio_meta" + 8760ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen " SET _data='/mnt/sdcard'||SUBSTR(_data,8) WHERE _data LIKE '/sdcard/%';"); 8770ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE audio_playlists" + 8780ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen " SET _data='/mnt/sdcard'||SUBSTR(_data,8) WHERE _data LIKE '/sdcard/%';"); 8790ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE images" + 8800ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen " SET _data='/mnt/sdcard'||SUBSTR(_data,8) WHERE _data LIKE '/sdcard/%';"); 8810ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE video" + 8820ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen " SET _data='/mnt/sdcard'||SUBSTR(_data,8) WHERE _data LIKE '/sdcard/%';"); 8830ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE videothumbnails" + 8840ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen " SET _data='/mnt/sdcard'||SUBSTR(_data,8) WHERE _data LIKE '/sdcard/%';"); 8850ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE thumbnails" + 8860ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen " SET _data='/mnt/sdcard'||SUBSTR(_data,8) WHERE _data LIKE '/sdcard/%';"); 8870ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE album_art" + 8880ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen " SET _data='/mnt/sdcard'||SUBSTR(_data,8) WHERE _data LIKE '/sdcard/%';"); 8890ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen 8900ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // Delete albums and artists, then clear the modification time on songs, which 8910ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // will cause the media scanner to rescan everything, rebuilding the artist and 8920ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // album tables along the way, while preserving playlists. 8930ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // We need this rescan because ICU also changed, and now generates different 8940ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // collation keys 8950ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE from albums"); 8960ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE from artists"); 8970ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE audio_meta SET date_modified=0;"); 8980ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen } 89984403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen 90084403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen if (fromVersion < 82) { 901acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // recreate this view with the correct "group by" specifier 90284403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen db.execSQL("DROP VIEW IF EXISTS artist_info"); 90384403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen db.execSQL("CREATE VIEW IF NOT EXISTS artist_info AS " + 90484403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen "SELECT artist_id AS _id, artist, artist_key, " + 905acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen "COUNT(DISTINCT album_key) AS number_of_albums, " + 90684403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen "COUNT(*) AS number_of_tracks FROM audio WHERE is_music=1 "+ 90784403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen "GROUP BY artist_key;"); 90884403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen } 909216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen 910acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen /* we skipped over version 83, and reverted versions 84, 85 and 86 */ 911ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen 912ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen if (fromVersion < 87) { 913ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen // The fastscroll thumb needs an index on the strings being displayed, 914ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen // otherwise the queries it does to determine the correct position 915ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen // becomes really inefficient 916022eb71bfe8ec65b8817eaa432a530194210ec23Marco Nelissen db.execSQL("CREATE INDEX IF NOT EXISTS title_idx on audio_meta(title);"); 917022eb71bfe8ec65b8817eaa432a530194210ec23Marco Nelissen db.execSQL("CREATE INDEX IF NOT EXISTS artist_idx on artists(artist);"); 918022eb71bfe8ec65b8817eaa432a530194210ec23Marco Nelissen db.execSQL("CREATE INDEX IF NOT EXISTS album_idx on albums(album);"); 919ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen } 920216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen 921acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen if (fromVersion < 88) { 922acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // Clean up a few more things from versions 84/85/86, and recreate 923acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // the few things worth keeping from those changes. 924acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS albums_update1;"); 925acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS albums_update2;"); 926acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS albums_update3;"); 927acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS albums_update4;"); 928acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS artist_update1;"); 929acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS artist_update2;"); 930acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS artist_update3;"); 931acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS artist_update4;"); 932acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP VIEw IF EXISTS album_artists;"); 933acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("CREATE INDEX IF NOT EXISTS album_id_idx on audio_meta(album_id);"); 934acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("CREATE INDEX IF NOT EXISTS artist_id_idx on audio_meta(artist_id);"); 935acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // For a given artist_id, provides the album_id for albums on 936acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // which the artist appears. 937acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("CREATE VIEW IF NOT EXISTS artists_albums_map AS " + 938acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen "SELECT DISTINCT artist_id, album_id FROM audio_meta;"); 939acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen } 940403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen 941403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen if (fromVersion < 89) { 942403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen updateBucketNames(db, "images"); 943403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen updateBucketNames(db, "video"); 944403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen } 945acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen sanityCheck(db, fromVersion); 9461d4a8ec9e1e62427088dc40f08872a10c863535eMarco Nelissen } 9471d4a8ec9e1e62427088dc40f08872a10c863535eMarco Nelissen 9481d4a8ec9e1e62427088dc40f08872a10c863535eMarco Nelissen /** 949216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen * Perform a simple sanity check on the database. Currently this tests 950216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen * whether all the _data entries in audio_meta are unique 951216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen */ 952216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen private static void sanityCheck(SQLiteDatabase db, int fromVersion) { 953216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen Cursor c1 = db.query("audio_meta", new String[] {"count(*)"}, 954216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen null, null, null, null, null); 955216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen Cursor c2 = db.query("audio_meta", new String[] {"count(distinct _data)"}, 956216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen null, null, null, null, null); 957216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen c1.moveToFirst(); 958216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen c2.moveToFirst(); 959216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen int num1 = c1.getInt(0); 960216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen int num2 = c2.getInt(0); 961216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen c1.close(); 962216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen c2.close(); 963216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen if (num1 != num2) { 964216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen Log.e(TAG, "audio_meta._data column is not unique while upgrading" + 965216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen " from schema " +fromVersion + " : " + num1 +"/" + num2); 966216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen // Delete all audio_meta rows so they will be rebuilt by the media scanner 967216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen db.execSQL("DELETE FROM audio_meta;"); 968216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen } 969702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 970702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 971702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static void recreateAudioView(SQLiteDatabase db) { 972702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Provides a unified audio/artist/album info view. 973702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Note that views are read-only, so we define a trigger to allow deletes. 974702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP VIEW IF EXISTS audio"); 975702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS audio_delete"); 976702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE VIEW IF NOT EXISTS audio as SELECT * FROM audio_meta " + 977702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "LEFT OUTER JOIN artists ON audio_meta.artist_id=artists.artist_id " + 978702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "LEFT OUTER JOIN albums ON audio_meta.album_id=albums.album_id;"); 979702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 980702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS audio_delete INSTEAD OF DELETE ON audio " + 981702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 982702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE from audio_meta where _id=old._id;" + 983702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE from audio_playlists_map where audio_id=old._id;" + 984702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE from audio_genres_map where audio_id=old._id;" + 985702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 986702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 98795ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen 988702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 989702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Iterate through the rows of a table in a database, ensuring that the bucket_id and 990702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * bucket_display_name columns are correct. 991702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param db 992702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param tableName 993702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 994702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static void updateBucketNames(SQLiteDatabase db, String tableName) { 995702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Rebuild the bucket_display_name column using the natural case rather than lower case. 996702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.beginTransaction(); 997702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 998702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String[] columns = {BaseColumns._ID, MediaColumns.DATA}; 999702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Cursor cursor = db.query(tableName, columns, null, null, null, null, null); 1000702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 1001702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final int idColumnIndex = cursor.getColumnIndex(BaseColumns._ID); 1002702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final int dataColumnIndex = cursor.getColumnIndex(MediaColumns.DATA); 1003702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project while (cursor.moveToNext()) { 1004702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String data = cursor.getString(dataColumnIndex); 1005702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(); 1006702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project computeBucketValues(data, values); 1007702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int rowId = cursor.getInt(idColumnIndex); 1008702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.update(tableName, values, "_id=" + rowId, null); 1009702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1010702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 1011702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project cursor.close(); 1012702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1013702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.setTransactionSuccessful(); 1014702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 1015702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.endTransaction(); 1016702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1017702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1018702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1019702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 1020702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Iterate through the rows of a table in a database, ensuring that the 1021702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * display name column has a value. 1022702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param db 1023702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param tableName 1024702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 1025702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static void updateDisplayName(SQLiteDatabase db, String tableName) { 1026702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Fill in default values for null displayName values 1027702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.beginTransaction(); 1028702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 1029702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String[] columns = {BaseColumns._ID, MediaColumns.DATA, MediaColumns.DISPLAY_NAME}; 1030702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Cursor cursor = db.query(tableName, columns, null, null, null, null, null); 1031702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 1032702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final int idColumnIndex = cursor.getColumnIndex(BaseColumns._ID); 1033702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final int dataColumnIndex = cursor.getColumnIndex(MediaColumns.DATA); 1034702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final int displayNameIndex = cursor.getColumnIndex(MediaColumns.DISPLAY_NAME); 1035702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(); 1036702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project while (cursor.moveToNext()) { 1037702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String displayName = cursor.getString(displayNameIndex); 1038702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (displayName == null) { 1039702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String data = cursor.getString(dataColumnIndex); 1040702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.clear(); 1041702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project computeDisplayName(data, values); 1042702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int rowId = cursor.getInt(idColumnIndex); 1043702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.update(tableName, values, "_id=" + rowId, null); 1044702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1045702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1046702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 1047702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project cursor.close(); 1048702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1049702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.setTransactionSuccessful(); 1050702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 1051702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.endTransaction(); 1052702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1053702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1054702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 1055702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param data The input path 1056702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param values the content values, where the bucked id name and bucket display name are updated. 1057702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 1058702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 1059702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1060702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static void computeBucketValues(String data, ContentValues values) { 1061702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File parentFile = new File(data).getParentFile(); 1062702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (parentFile == null) { 1063702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project parentFile = new File("/"); 1064702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1065702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1066702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Lowercase the path for hashing. This avoids duplicate buckets if the 1067702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // filepath case is changed externally. 1068702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Keep the original case for display. 1069702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String path = parentFile.toString().toLowerCase(); 1070702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String name = parentFile.getName(); 1071702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1072702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Note: the BUCKET_ID and BUCKET_DISPLAY_NAME attributes are spelled the 1073702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // same for both images and video. However, for backwards-compatibility reasons 1074702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // there is no common base class. We use the ImageColumns version here 1075702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(ImageColumns.BUCKET_ID, path.hashCode()); 1076702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(ImageColumns.BUCKET_DISPLAY_NAME, name); 1077702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1078702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1079702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 1080702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param data The input path 1081702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param values the content values, where the display name is updated. 1082702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 1083702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 1084702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static void computeDisplayName(String data, ContentValues values) { 1085702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String s = (data == null ? "" : data.toString()); 1086702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int idx = s.lastIndexOf('/'); 1087702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (idx >= 0) { 1088702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project s = s.substring(idx + 1); 1089702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1090702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put("_display_name", s); 1091702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1092702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1093b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen /** 1094498b62c2912302a23532c73a028a7684c5df33caRay Chen * Copy taken time from date_modified if we lost the original value (e.g. after factory reset) 1095498b62c2912302a23532c73a028a7684c5df33caRay Chen * This works for both video and image tables. 1096b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen * 1097b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen * @param values the content values, where taken time is updated. 1098b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen */ 1099b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen private static void computeTakenTime(ContentValues values) { 1100b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen if (! values.containsKey(Images.Media.DATE_TAKEN)) { 1101b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen // This only happens when MediaScanner finds an image file that doesn't have any useful 1102b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen // reference to get this value. (e.g. GPSTimeStamp) 1103498b62c2912302a23532c73a028a7684c5df33caRay Chen Long lastModified = values.getAsLong(MediaColumns.DATE_MODIFIED); 1104b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen if (lastModified != null) { 1105b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen values.put(Images.Media.DATE_TAKEN, lastModified * 1000); 1106b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen } 1107b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen } 1108b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen } 1109b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen 1110b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen /** 1111b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen * This method blocks until thumbnail is ready. 1112b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen * 1113b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen * @param thumbUri 1114b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen * @return 1115b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen */ 1116b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private boolean waitForThumbnailReady(Uri origUri) { 1117b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen Cursor c = this.query(origUri, new String[] { ImageColumns._ID, ImageColumns.DATA, 1118b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen ImageColumns.MINI_THUMB_MAGIC}, null, null, null); 1119b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (c == null) return false; 1120b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1121b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen boolean result = false; 1122b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1123b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (c.moveToFirst()) { 1124e263c2a4b880ef8a5314bb4379c74bf5f9292bd0Ray Chen long id = c.getLong(0); 1125b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen String path = c.getString(1); 1126b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen long magic = c.getLong(2); 1127b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 11289299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen MediaThumbRequest req = requestMediaThumbnail(path, origUri, 11299299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen MediaThumbRequest.PRIORITY_HIGH, magic); 11309299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen if (req == null) { 11319299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen return false; 11329299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen } 11339299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen synchronized (req) { 11349299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen try { 11359299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen while (req.mState == MediaThumbRequest.State.WAIT) { 11369299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen req.wait(); 113720434e032e498b716f87cce2f23dd646819218bfRay Chen } 11389299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen } catch (InterruptedException e) { 11399299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen Log.w(TAG, e); 11409299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen } 11419299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen if (req.mState == MediaThumbRequest.State.DONE) { 11429299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen result = true; 1143b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1144b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1145b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1146b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen c.close(); 1147b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1148b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return result; 1149b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1150b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1151e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen private boolean matchThumbRequest(MediaThumbRequest req, int pid, long id, long gid, 1152e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen boolean isVideo) { 1153e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen boolean cancelAllOrigId = (id == -1); 1154e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen boolean cancelAllGroupId = (gid == -1); 1155e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen return (req.mCallingPid == pid) && 1156e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen (cancelAllGroupId || req.mGroupId == gid) && 1157e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen (cancelAllOrigId || req.mOrigId == id) && 1158e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen (req.mIsVideo == isVideo); 1159e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen } 1160e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen 1161b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private boolean queryThumbnail(SQLiteQueryBuilder qb, Uri uri, String table, 1162b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen String column, boolean hasThumbnailId) { 1163b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen qb.setTables(table); 1164b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (hasThumbnailId) { 1165b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // For uri dispatched to this method, the 4th path segment is always 1166b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // the thumbnail id. 1167b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen qb.appendWhere("_id = " + uri.getPathSegments().get(3)); 1168b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // client already knows which thumbnail it wants, bypass it. 1169b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return true; 1170b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1171b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen String origId = uri.getQueryParameter("orig_id"); 1172b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // We can't query ready_flag unless we know original id 1173b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (origId == null) { 1174b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // this could be thumbnail query for other purpose, bypass it. 1175b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return true; 1176b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1177b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1178b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen boolean needBlocking = "1".equals(uri.getQueryParameter("blocking")); 117920434e032e498b716f87cce2f23dd646819218bfRay Chen boolean cancelRequest = "1".equals(uri.getQueryParameter("cancel")); 1180e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen Uri origUri = uri.buildUpon().encodedPath( 1181e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen uri.getPath().replaceFirst("thumbnails", "media")) 1182e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen .appendPath(origId).build(); 1183b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1184b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (needBlocking && !waitForThumbnailReady(origUri)) { 118520434e032e498b716f87cce2f23dd646819218bfRay Chen Log.w(TAG, "original media doesn't exist or it's canceled."); 1186b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return false; 118720434e032e498b716f87cce2f23dd646819218bfRay Chen } else if (cancelRequest) { 1188e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen String groupId = uri.getQueryParameter("group_id"); 1189e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen boolean isVideo = "video".equals(uri.getPathSegments().get(1)); 119020434e032e498b716f87cce2f23dd646819218bfRay Chen int pid = Binder.getCallingPid(); 119120434e032e498b716f87cce2f23dd646819218bfRay Chen long id = -1; 1192e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen long gid = -1; 1193e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen 119420434e032e498b716f87cce2f23dd646819218bfRay Chen try { 119520434e032e498b716f87cce2f23dd646819218bfRay Chen id = Long.parseLong(origId); 1196e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen gid = Long.parseLong(groupId); 119720434e032e498b716f87cce2f23dd646819218bfRay Chen } catch (NumberFormatException ex) { 119820434e032e498b716f87cce2f23dd646819218bfRay Chen // invalid cancel request 119920434e032e498b716f87cce2f23dd646819218bfRay Chen return false; 120020434e032e498b716f87cce2f23dd646819218bfRay Chen } 1201e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen 120220434e032e498b716f87cce2f23dd646819218bfRay Chen synchronized (mMediaThumbQueue) { 1203e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen if (mCurrentThumbRequest != null && 1204e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen matchThumbRequest(mCurrentThumbRequest, pid, id, gid, isVideo)) { 120520434e032e498b716f87cce2f23dd646819218bfRay Chen synchronized (mCurrentThumbRequest) { 120620434e032e498b716f87cce2f23dd646819218bfRay Chen mCurrentThumbRequest.mState = MediaThumbRequest.State.CANCEL; 120720434e032e498b716f87cce2f23dd646819218bfRay Chen mCurrentThumbRequest.notifyAll(); 120820434e032e498b716f87cce2f23dd646819218bfRay Chen } 120920434e032e498b716f87cce2f23dd646819218bfRay Chen } 121020434e032e498b716f87cce2f23dd646819218bfRay Chen for (MediaThumbRequest mtq : mMediaThumbQueue) { 1211e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen if (matchThumbRequest(mtq, pid, id, gid, isVideo)) { 121220434e032e498b716f87cce2f23dd646819218bfRay Chen synchronized (mtq) { 121320434e032e498b716f87cce2f23dd646819218bfRay Chen mtq.mState = MediaThumbRequest.State.CANCEL; 121420434e032e498b716f87cce2f23dd646819218bfRay Chen mtq.notifyAll(); 121520434e032e498b716f87cce2f23dd646819218bfRay Chen } 121620434e032e498b716f87cce2f23dd646819218bfRay Chen 121720434e032e498b716f87cce2f23dd646819218bfRay Chen mMediaThumbQueue.remove(mtq); 121820434e032e498b716f87cce2f23dd646819218bfRay Chen } 121920434e032e498b716f87cce2f23dd646819218bfRay Chen } 122020434e032e498b716f87cce2f23dd646819218bfRay Chen } 1221b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1222b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1223b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (origId != null) { 1224b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen qb.appendWhere(column + " = " + origId); 1225b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1226b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return true; 1227b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1228b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen @SuppressWarnings("fallthrough") 1229702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 1230702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public Cursor query(Uri uri, String[] projectionIn, String selection, 1231702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String[] selectionArgs, String sort) { 1232702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int table = URI_MATCHER.match(uri); 1233702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 123401a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen // Log.v(TAG, "query: uri="+uri+", selection="+selection); 1235702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // handle MEDIA_SCANNER before calling getDatabaseForUri() 1236702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (table == MEDIA_SCANNER) { 1237702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (mMediaScannerVolume == null) { 1238702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return null; 1239702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 1240702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // create a cursor to return volume currently being scanned by the media scanner 12410027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen MatrixCursor c = new MatrixCursor(new String[] {MediaStore.MEDIA_SCANNER_VOLUME}); 12420027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen c.addRow(new String[] {mMediaScannerVolume}); 12430027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen return c; 1244702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1245702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1246702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 12470027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen // Used temporarily (until we have unique media IDs) to get an identifier 12480027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen // for the current sd card, so that the music app doesn't have to use the 12490027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen // non-public getFatVolumeId method 12500027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen if (table == FS_ID) { 12510027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen MatrixCursor c = new MatrixCursor(new String[] {"fsid"}); 12520027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen c.addRow(new Integer[] {mVolumeId}); 12530027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen return c; 12540027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen } 12550027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen 1256702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String groupBy = null; 1257702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DatabaseHelper database = getDatabaseForUri(uri); 1258702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (database == null) { 1259702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return null; 1260702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1261702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteDatabase db = database.getReadableDatabase(); 1262702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 12634574e03055af60fada50481f2b34e19a687d5866Marco Nelissen String limit = uri.getQueryParameter("limit"); 1264b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen boolean hasThumbnailId = false; 1265702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1266702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (table) { 1267702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA: 1268702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("images"); 1269702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (uri.getQueryParameter("distinct") != null) 1270702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setDistinct(true); 1271702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1272702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // set the project map so that data dir is prepended to _data. 1273702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project //qb.setProjectionMap(mImagesProjectionMap, true); 1274702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1275702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1276702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA_ID: 1277702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("images"); 1278702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (uri.getQueryParameter("distinct") != null) 1279702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setDistinct(true); 1280702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1281702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // set the project map so that data dir is prepended to _data. 1282702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project //qb.setProjectionMap(mImagesProjectionMap, true); 1283702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id = " + uri.getPathSegments().get(3)); 1284702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1285702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1286702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_THUMBNAILS_ID: 1287b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen hasThumbnailId = true; 1288b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case IMAGES_THUMBNAILS: 1289b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (!queryThumbnail(qb, uri, "thumbnails", "image_id", hasThumbnailId)) { 1290b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return null; 1291b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1292702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1293702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1294702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA: 1295ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen if (projectionIn.length == 1 && selectionArgs == null 1296ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen && (selection == null || selection.equalsIgnoreCase("is_music=1") 1297ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen || selection.equalsIgnoreCase("is_podcast=1") ) 1298ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen && projectionIn[0].equalsIgnoreCase("count(*)") ) { 1299ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen //Log.i("@@@@", "taking fast path for counting songs"); 1300ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.setTables("audio_meta"); 1301ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen } else { 1302ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.setTables("audio"); 1303ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen } 1304702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1305702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1306702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID: 1307702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio"); 1308702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id=" + uri.getPathSegments().get(3)); 1309702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1310702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1311702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES: 1312702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_genres"); 1313702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id IN (SELECT genre_id FROM " + 1314702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_genres_map WHERE audio_id = " + 1315702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project uri.getPathSegments().get(3) + ")"); 1316702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1317702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1318702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES_ID: 1319702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_genres"); 1320702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id=" + uri.getPathSegments().get(5)); 1321702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1322702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1323702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS: 1324702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_playlists"); 1325702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id IN (SELECT playlist_id FROM " + 1326702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_playlists_map WHERE audio_id = " + 1327702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project uri.getPathSegments().get(3) + ")"); 1328702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1329702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1330702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS_ID: 1331702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_playlists"); 1332702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id=" + uri.getPathSegments().get(5)); 1333702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1334702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1335702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES: 1336702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_genres"); 1337702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1338702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1339702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID: 1340702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_genres"); 1341702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id=" + uri.getPathSegments().get(3)); 1342702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1343702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1344702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID_MEMBERS: 1345702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio"); 1346702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id IN (SELECT audio_id FROM " + 1347702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_genres_map WHERE genre_id = " + 1348702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project uri.getPathSegments().get(3) + ")"); 1349702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1350702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1351702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID_MEMBERS_ID: 1352702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio"); 1353702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id=" + uri.getPathSegments().get(5)); 1354702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1355702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1356702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS: 1357702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_playlists"); 1358702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1359702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1360702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID: 1361702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_playlists"); 1362702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id=" + uri.getPathSegments().get(3)); 1363702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1364702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1365702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS: 136697e61d89d90a1bd6989a254660aa80553662e002Marco Nelissen if (projectionIn != null) { 136797e61d89d90a1bd6989a254660aa80553662e002Marco Nelissen for (int i = 0; i < projectionIn.length; i++) { 136897e61d89d90a1bd6989a254660aa80553662e002Marco Nelissen if (projectionIn[i].equals("_id")) { 136997e61d89d90a1bd6989a254660aa80553662e002Marco Nelissen projectionIn[i] = "audio_playlists_map._id AS _id"; 137097e61d89d90a1bd6989a254660aa80553662e002Marco Nelissen } 1371702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1372702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1373702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_playlists_map, audio"); 1374702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("audio._id = audio_id AND playlist_id = " 1375702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project + uri.getPathSegments().get(3)); 1376702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1377702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1378702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS_ID: 1379702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio"); 1380702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id=" + uri.getPathSegments().get(5)); 1381702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1382702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1383702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA: 1384702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("video"); 1385702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1386702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1387702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA_ID: 1388702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("video"); 1389702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id=" + uri.getPathSegments().get(3)); 1390702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1391702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1392b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case VIDEO_THUMBNAILS_ID: 1393b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen hasThumbnailId = true; 1394b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case VIDEO_THUMBNAILS: 1395b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (!queryThumbnail(qb, uri, "videothumbnails", "video_id", hasThumbnailId)) { 1396b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return null; 1397b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1398b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen break; 1399b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1400702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ARTISTS: 1401ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen if (projectionIn.length == 1 && selectionArgs == null 1402ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen && (selection == null || selection.length() == 0) 1403ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen && projectionIn[0].equalsIgnoreCase("count(*)") ) { 1404ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen //Log.i("@@@@", "taking fast path for counting artists"); 1405ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.setTables("audio_meta"); 1406ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen projectionIn[0] = "count(distinct artist_id)"; 1407ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.appendWhere("is_music=1"); 1408ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen } else { 1409ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.setTables("artist_info"); 1410ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen } 1411702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1412702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1413702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ARTISTS_ID: 1414702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("artist_info"); 1415702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id=" + uri.getPathSegments().get(3)); 1416702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1417702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1418702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ARTISTS_ID_ALBUMS: 1419702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String aid = uri.getPathSegments().get(3); 1420acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen qb.setTables("audio LEFT OUTER JOIN album_art ON" + 1421acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen " audio.album_id=album_art.album_id"); 1422acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen qb.appendWhere("is_music=1 AND audio.album_id IN (SELECT album_id FROM " + 1423acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen "artists_albums_map WHERE artist_id = " + 1424acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen aid + ")"); 1425acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen groupBy = "audio.album_id"; 1426702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Albums.NUMBER_OF_SONGS_FOR_ARTIST, 1427acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen "count(CASE WHEN artist_id==" + aid + " THEN 'foo' ELSE NULL END) AS " + 1428702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.Audio.Albums.NUMBER_OF_SONGS_FOR_ARTIST); 1429702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setProjectionMap(sArtistAlbumsMap); 1430702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1431702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1432702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ALBUMS: 1433ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen if (projectionIn.length == 1 && selectionArgs == null 1434ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen && (selection == null || selection.length() == 0) 1435ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen && projectionIn[0].equalsIgnoreCase("count(*)") ) { 1436ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen //Log.i("@@@@", "taking fast path for counting albums"); 1437ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.setTables("audio_meta"); 1438ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen projectionIn[0] = "count(distinct album_id)"; 1439ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.appendWhere("is_music=1"); 1440ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen } else { 1441ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.setTables("album_info"); 1442ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen } 1443702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1444702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1445702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ALBUMS_ID: 1446702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("album_info"); 1447702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id=" + uri.getPathSegments().get(3)); 1448702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1449702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1450702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ALBUMART_ID: 1451702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("album_art"); 1452702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("album_id=" + uri.getPathSegments().get(3)); 1453702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1454702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1455a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen case AUDIO_SEARCH_LEGACY: 1456a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen Log.w(TAG, "Legacy media search Uri used. Please update your code."); 1457a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // fall through 1458a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen case AUDIO_SEARCH_FANCY: 1459a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen case AUDIO_SEARCH_BASIC: 1460a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen return doAudioSearch(db, qb, uri, projectionIn, selection, selectionArgs, sort, 14614574e03055af60fada50481f2b34e19a687d5866Marco Nelissen table, limit); 1462702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1463702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project default: 1464702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalStateException("Unknown URL: " + uri.toString()); 1465702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1466702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 14674d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen // Log.v(TAG, "query = "+ qb.buildQuery(projectionIn, selection, selectionArgs, groupBy, null, sort, limit)); 1468702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Cursor c = qb.query(db, projectionIn, selection, 14694574e03055af60fada50481f2b34e19a687d5866Marco Nelissen selectionArgs, groupBy, null, sort, limit); 1470b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1471702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (c != null) { 1472702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project c.setNotificationUri(getContext().getContentResolver(), uri); 1473702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1474b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1475702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return c; 1476702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1477702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1478702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private Cursor doAudioSearch(SQLiteDatabase db, SQLiteQueryBuilder qb, 1479702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Uri uri, String[] projectionIn, String selection, 14804574e03055af60fada50481f2b34e19a687d5866Marco Nelissen String[] selectionArgs, String sort, int mode, 14814574e03055af60fada50481f2b34e19a687d5866Marco Nelissen String limit) { 1482702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1483a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen String mSearchString = uri.toString().endsWith("/") ? "" : uri.getLastPathSegment(); 1484702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mSearchString = mSearchString.replaceAll(" ", " ").trim().toLowerCase(); 1485702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1486702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String [] searchWords = mSearchString.length() > 0 ? 1487702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mSearchString.split(" ") : new String[0]; 1488a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen String [] wildcardWords = new String[searchWords.length]; 1489702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Collator col = Collator.getInstance(); 1490702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project col.setStrength(Collator.PRIMARY); 1491702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int len = searchWords.length; 1492702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project for (int i = 0; i < len; i++) { 1493702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Because we match on individual words here, we need to remove words 1494702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // like 'a' and 'the' that aren't part of the keys. 1495a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen wildcardWords[i] = 1496702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project (searchWords[i].equals("a") || searchWords[i].equals("an") || 1497702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project searchWords[i].equals("the")) ? "%" : 1498702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project '%' + MediaStore.Audio.keyFor(searchWords[i]) + '%'; 1499702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1500702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1501a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen String where = ""; 1502a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen for (int i = 0; i < searchWords.length; i++) { 1503a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen if (i == 0) { 1504a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen where = "match LIKE ?"; 1505a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen } else { 1506a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen where += " AND match LIKE ?"; 1507702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1508702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1509702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1510a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen qb.setTables("search"); 1511a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen String [] cols; 1512a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen if (mode == AUDIO_SEARCH_FANCY) { 1513a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen cols = mSearchColsFancy; 1514a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen } else if (mode == AUDIO_SEARCH_BASIC) { 1515a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen cols = mSearchColsBasic; 1516a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen } else { 1517a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen cols = mSearchColsLegacy; 1518702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 15194574e03055af60fada50481f2b34e19a687d5866Marco Nelissen return qb.query(db, cols, where, wildcardWords, null, null, null, limit); 1520702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1521702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1522702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 1523702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public String getType(Uri url) 1524702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project { 1525702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (URI_MATCHER.match(url)) { 1526702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA_ID: 1527702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID: 1528702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID_MEMBERS_ID: 1529702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS_ID: 1530702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA_ID: 153126f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen Cursor c = null; 153226f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen try { 153326f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen c = query(url, MIME_TYPE_PROJECTION, null, null, null); 153426f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen if (c != null && c.getCount() == 1) { 153526f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen c.moveToFirst(); 153626f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen String mimeType = c.getString(1); 153726f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen c.deactivate(); 153826f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen return mimeType; 153926f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen } 154026f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen } finally { 154126f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen if (c != null) { 154226f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen c.close(); 154326f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen } 1544702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1545702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1546702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1547702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA: 1548702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_THUMBNAILS: 1549702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Images.Media.CONTENT_TYPE; 1550702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_THUMBNAILS_ID: 1551702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return "image/jpeg"; 1552702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1553702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA: 1554702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID_MEMBERS: 1555702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS: 1556702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Audio.Media.CONTENT_TYPE; 1557702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1558702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES: 1559702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES: 1560702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Audio.Genres.CONTENT_TYPE; 1561702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID: 1562702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES_ID: 1563702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Audio.Genres.ENTRY_CONTENT_TYPE; 1564702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS: 1565702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS: 1566702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Audio.Playlists.CONTENT_TYPE; 1567702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID: 1568702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS_ID: 1569702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Audio.Playlists.ENTRY_CONTENT_TYPE; 1570702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1571702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA: 1572702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Video.Media.CONTENT_TYPE; 1573702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1574702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalStateException("Unknown URL"); 1575702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1576702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1577702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 1578702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Ensures there is a file in the _data column of values, if one isn't 1579702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * present a new file is created. 1580702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 1581702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param initialValues the values passed to insert by the caller 1582702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @return the new values 1583702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 1584702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private ContentValues ensureFile(boolean internal, ContentValues initialValues, 1585702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String preferredExtension, String directoryName) { 1586702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values; 1587702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String file = initialValues.getAsString("_data"); 1588702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (TextUtils.isEmpty(file)) { 1589702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project file = generateFileName(internal, preferredExtension, directoryName); 1590702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values = new ContentValues(initialValues); 1591702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put("_data", file); 1592702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 1593702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values = initialValues; 1594702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1595702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1596702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!ensureFileExists(file)) { 1597702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalStateException("Unable to create new file: " + file); 1598702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1599702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return values; 1600702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1601702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1602702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 1603702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public int bulkInsert(Uri uri, ContentValues values[]) { 1604702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int match = URI_MATCHER.match(uri); 1605702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (match == VOLUMES) { 1606702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return super.bulkInsert(uri, values); 1607702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1608702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DatabaseHelper database = getDatabaseForUri(uri); 1609702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (database == null) { 1610702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException( 1611702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Unknown URI: " + uri); 1612702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1613702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteDatabase db = database.getWritableDatabase(); 1614ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen 1615ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen if (match == AUDIO_PLAYLISTS_ID || match == AUDIO_PLAYLISTS_ID_MEMBERS) { 1616ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen return playlistBulkInsert(db, uri, values); 1617ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen } 1618ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen 1619702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.beginTransaction(); 1620702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int numInserted = 0; 1621702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 1622702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int len = values.length; 1623702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project for (int i = 0; i < len; i++) { 1624702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project insertInternal(uri, values[i]); 1625702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1626702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project numInserted = len; 1627702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.setTransactionSuccessful(); 1628702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 1629702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.endTransaction(); 1630702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1631702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 1632702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return numInserted; 1633702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1634702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1635702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 1636702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public Uri insert(Uri uri, ContentValues initialValues) 1637702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project { 1638702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Uri newUri = insertInternal(uri, initialValues); 1639702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (newUri != null) { 1640702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 1641702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1642702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return newUri; 1643702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1644702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1645ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen private int playlistBulkInsert(SQLiteDatabase db, Uri uri, ContentValues values[]) { 1646ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen DatabaseUtils.InsertHelper helper = 1647ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen new DatabaseUtils.InsertHelper(db, "audio_playlists_map"); 16488b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen int audioidcolidx = helper.getColumnIndex(MediaStore.Audio.Playlists.Members.AUDIO_ID); 16498b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen int playlistididx = helper.getColumnIndex(Audio.Playlists.Members.PLAYLIST_ID); 16508b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen int playorderidx = helper.getColumnIndex(MediaStore.Audio.Playlists.Members.PLAY_ORDER); 16518b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen long playlistId = Long.parseLong(uri.getPathSegments().get(3)); 1652ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen 1653ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen db.beginTransaction(); 1654ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen int numInserted = 0; 1655ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen try { 1656ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen int len = values.length; 1657ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen for (int i = 0; i < len; i++) { 16588b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen helper.prepareForInsert(); 16598b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen // getting the raw Object and converting it long ourselves saves 16608b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen // an allocation (the alternative is ContentValues.getAsLong, which 16618b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen // returns a Long object) 16628b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen long audioid = ((Number) values[i].get( 16638b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen MediaStore.Audio.Playlists.Members.AUDIO_ID)).longValue(); 16648b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen helper.bind(audioidcolidx, audioid); 16658b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen helper.bind(playlistididx, playlistId); 16668b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen // convert to int ourselves to save an allocation. 16678b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen int playorder = ((Number) values[i].get( 16688b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen MediaStore.Audio.Playlists.Members.PLAY_ORDER)).intValue(); 16698b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen helper.bind(playorderidx, playorder); 16708b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen helper.execute(); 1671ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen } 1672ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen numInserted = len; 1673ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen db.setTransactionSuccessful(); 1674ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen } finally { 1675ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen db.endTransaction(); 1676ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen helper.close(); 1677ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen } 1678ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen getContext().getContentResolver().notifyChange(uri, null); 1679ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen return numInserted; 1680ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen } 1681ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen 1682702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private Uri insertInternal(Uri uri, ContentValues initialValues) { 1683702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long rowId; 1684702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int match = URI_MATCHER.match(uri); 1685702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1686b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // Log.v(TAG, "insertInternal: "+uri+", initValues="+initialValues); 1687702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // handle MEDIA_SCANNER before calling getDatabaseForUri() 1688702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (match == MEDIA_SCANNER) { 1689702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mMediaScannerVolume = initialValues.getAsString(MediaStore.MEDIA_SCANNER_VOLUME); 1690702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return MediaStore.getMediaScannerUri(); 1691702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1692702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1693702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Uri newUri = null; 1694702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DatabaseHelper database = getDatabaseForUri(uri); 1695702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (database == null && match != VOLUMES) { 1696702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException( 1697702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Unknown URI: " + uri); 1698702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1699702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteDatabase db = (match == VOLUMES ? null : database.getWritableDatabase()); 1700702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1701702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (initialValues == null) { 1702702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project initialValues = new ContentValues(); 1703702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1704702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1705702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (match) { 1706702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA: { 1707702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = ensureFile(database.mInternal, initialValues, ".jpg", "DCIM/Camera"); 1708702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1709702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(MediaStore.MediaColumns.DATE_ADDED, System.currentTimeMillis() / 1000); 1710702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String data = values.getAsString(MediaColumns.DATA); 1711702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (! values.containsKey(MediaColumns.DISPLAY_NAME)) { 1712702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project computeDisplayName(data, values); 1713702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1714702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project computeBucketValues(data, values); 1715b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen computeTakenTime(values); 1716702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert("images", "name", values); 1717702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1718702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 1719702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId( 1720702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Images.Media.getContentUri(uri.getPathSegments().get(0)), rowId); 17219299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen requestMediaThumbnail(data, newUri, MediaThumbRequest.PRIORITY_NORMAL, 0); 1722702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1723702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1724702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1725702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1726b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // This will be triggered by requestMediaThumbnail (see getThumbnailUri) 1727702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_THUMBNAILS: { 1728b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen ContentValues values = ensureFile(database.mInternal, initialValues, ".jpg", 1729b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "DCIM/.thumbnails"); 1730702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert("thumbnails", "name", values); 1731702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 1732702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(Images.Thumbnails. 1733702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContentUri(uri.getPathSegments().get(0)), rowId); 1734702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1735702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1736702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1737702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1738b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // This is currently only used by MICRO_KIND video thumbnail (see getThumbnailUri) 1739b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case VIDEO_THUMBNAILS: { 1740b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen ContentValues values = ensureFile(database.mInternal, initialValues, ".jpg", 1741b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "DCIM/.thumbnails"); 1742b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen rowId = db.insert("videothumbnails", "name", values); 1743b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (rowId > 0) { 1744b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen newUri = ContentUris.withAppendedId(Video.Thumbnails. 1745b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen getContentUri(uri.getPathSegments().get(0)), rowId); 1746b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1747b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen break; 1748b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1749b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1750702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA: { 1751702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // SQLite Views are read-only, so we need to deconstruct this 1752702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // insert and do inserts into the underlying tables. 1753702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // If doing this here turns out to be a performance bottleneck, 1754702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // consider moving this to native code and using triggers on 1755702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // the view. 1756702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(initialValues); 1757702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1758acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // TODO Remove this and actually store the album_artist in the 1759acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // database. For now this is here so the media scanner can start 1760acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // sending us the album_artist, even though it's not in the db yet. 1761acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen values.remove(MediaStore.Audio.Media.ALBUM_ARTIST); 1762acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen 1763702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Insert the artist into the artist table and remove it from 1764702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // the input values 1765702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Object so = values.get("artist"); 1766702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String s = (so == null ? "" : so.toString()); 1767702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.remove("artist"); 1768702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long artistRowId; 1769702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project HashMap<String, Long> artistCache = database.mArtistCache; 177059948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen String path = values.getAsString("_data"); 1771702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized(artistCache) { 1772702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Long temp = artistCache.get(s); 1773702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (temp == null) { 1774702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project artistRowId = getKeyIdForName(db, "artists", "artist_key", "artist", 1775a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen s, s, path, 0, null, artistCache, uri); 1776702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 1777702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project artistRowId = temp.longValue(); 1778702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1779702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1780a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen String artist = s; 1781702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1782702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Do the same for the album field 1783702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project so = values.get("album"); 1784702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project s = (so == null ? "" : so.toString()); 1785702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.remove("album"); 1786702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long albumRowId; 1787702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project HashMap<String, Long> albumCache = database.mAlbumCache; 1788702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized(albumCache) { 178959948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen int albumhash = path.substring(0, path.lastIndexOf('/')).hashCode(); 179059948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen String cacheName = s + albumhash; 179159948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen Long temp = albumCache.get(cacheName); 1792702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (temp == null) { 1793702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project albumRowId = getKeyIdForName(db, "albums", "album_key", "album", 1794a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen s, cacheName, path, albumhash, artist, albumCache, uri); 1795702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 1796702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project albumRowId = temp; 1797702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1798702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1799702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1800702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put("artist_id", Integer.toString((int)artistRowId)); 1801702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put("album_id", Integer.toString((int)albumRowId)); 1802702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project so = values.getAsString("title"); 1803702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project s = (so == null ? "" : so.toString()); 1804702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put("title_key", MediaStore.Audio.keyFor(s)); 1805358cfed9391de9b39ecb2a3dbefcf5e392915954Marco Nelissen // do a final trim of the title, in case it started with the special 1806358cfed9391de9b39ecb2a3dbefcf5e392915954Marco Nelissen // "sort first" character (ascii \001) 1807358cfed9391de9b39ecb2a3dbefcf5e392915954Marco Nelissen values.remove("title"); 1808358cfed9391de9b39ecb2a3dbefcf5e392915954Marco Nelissen values.put("title", s.trim()); 1809702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1810702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project computeDisplayName(values.getAsString("_data"), values); 1811702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(MediaStore.MediaColumns.DATE_ADDED, System.currentTimeMillis() / 1000); 1812702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1813702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert("audio_meta", "duration", values); 1814702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 1815702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(Audio.Media.getContentUri(uri.getPathSegments().get(0)), rowId); 1816702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1817702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1818702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1819702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1820702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES: { 1821702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Long audioId = Long.parseLong(uri.getPathSegments().get(2)); 1822702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(initialValues); 1823702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(Audio.Genres.Members.AUDIO_ID, audioId); 1824ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen rowId = db.insert("audio_genres_map", "genre_id", values); 1825702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 1826702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(uri, rowId); 1827702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1828702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1829702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1830702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1831702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS: { 1832702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Long audioId = Long.parseLong(uri.getPathSegments().get(2)); 1833702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(initialValues); 1834702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(Audio.Playlists.Members.AUDIO_ID, audioId); 1835702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert("audio_playlists_map", "playlist_id", 1836702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values); 1837702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 1838702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(uri, rowId); 1839702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1840702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1841702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1842702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1843702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES: { 1844702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert("audio_genres", "audio_id", initialValues); 1845702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 1846702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(Audio.Genres.getContentUri(uri.getPathSegments().get(0)), rowId); 1847702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1848702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1849702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1850702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1851702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID_MEMBERS: { 1852702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Long genreId = Long.parseLong(uri.getPathSegments().get(3)); 1853702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(initialValues); 1854702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(Audio.Genres.Members.GENRE_ID, genreId); 1855702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert("audio_genres_map", "genre_id", values); 1856702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 1857702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(uri, rowId); 1858702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1859702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1860702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1861702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1862702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS: { 1863702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(initialValues); 1864702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(MediaStore.Audio.Playlists.DATE_ADDED, System.currentTimeMillis() / 1000); 1865702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert("audio_playlists", "name", initialValues); 1866702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 1867702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(Audio.Playlists.getContentUri(uri.getPathSegments().get(0)), rowId); 1868702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1869702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1870702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1871702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1872702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID: 1873702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS: { 1874702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Long playlistId = Long.parseLong(uri.getPathSegments().get(3)); 1875702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(initialValues); 1876702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(Audio.Playlists.Members.PLAYLIST_ID, playlistId); 1877ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen rowId = db.insert("audio_playlists_map", "playlist_id", values); 1878702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 1879702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(uri, rowId); 1880702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1881702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1882702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1883702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1884702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA: { 1885702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = ensureFile(database.mInternal, initialValues, ".3gp", "video"); 1886702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String data = values.getAsString("_data"); 1887702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project computeDisplayName(data, values); 1888702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project computeBucketValues(data, values); 1889702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(MediaStore.MediaColumns.DATE_ADDED, System.currentTimeMillis() / 1000); 1890498b62c2912302a23532c73a028a7684c5df33caRay Chen computeTakenTime(values); 1891702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert("video", "artist", values); 1892702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 1893b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen newUri = ContentUris.withAppendedId(Video.Media.getContentUri( 1894b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen uri.getPathSegments().get(0)), rowId); 18959299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen requestMediaThumbnail(data, newUri, MediaThumbRequest.PRIORITY_NORMAL, 0); 1896702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1897702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1898702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1899702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1900702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ALBUMART: 1901702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (database.mInternal) { 1902702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException("no internal album art allowed"); 1903702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1904702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = null; 1905702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 1906702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values = ensureFile(false, initialValues, "", ALBUM_THUMB_FOLDER); 1907702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } catch (IllegalStateException ex) { 1908702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // probably no more room to store albumthumbs 1909702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values = initialValues; 1910702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1911702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert("album_art", "_data", values); 1912702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 1913702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(uri, rowId); 1914702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1915702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1916702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1917702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VOLUMES: 1918702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return attachVolume(initialValues.getAsString("name")); 1919702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1920702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project default: 1921702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException("Invalid URI " + uri); 1922702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1923702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1924702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return newUri; 1925702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1926702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1927cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen @Override 1928cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) 1929cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen throws OperationApplicationException { 1930cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen 1931cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen // The operations array provides no overall information about the URI(s) being operated 1932cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen // on, so begin a transaction for ALL of the databases. 1933cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen DatabaseHelper ihelper = getDatabaseForUri(MediaStore.Audio.Media.INTERNAL_CONTENT_URI); 1934cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen DatabaseHelper ehelper = getDatabaseForUri(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI); 1935cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen SQLiteDatabase idb = ihelper.getWritableDatabase(); 1936cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen idb.beginTransaction(); 1937cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen SQLiteDatabase edb = null; 1938cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen if (ehelper != null) { 1939cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen edb = ehelper.getWritableDatabase(); 1940cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen edb.beginTransaction(); 1941cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen } 1942cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen try { 1943cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen ContentProviderResult[] result = super.applyBatch(operations); 1944cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen idb.setTransactionSuccessful(); 1945cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen if (edb != null) { 1946cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen edb.setTransactionSuccessful(); 1947cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen } 1948cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen // Rather than sending targeted change notifications for every Uri 1949cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen // affected by the batch operation, just invalidate the entire internal 1950cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen // and external name space. 1951cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen ContentResolver res = getContext().getContentResolver(); 1952cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen res.notifyChange(Uri.parse("content://media/"), null); 1953cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen return result; 1954cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen } finally { 1955cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen idb.endTransaction(); 1956cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen if (edb != null) { 1957cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen edb.endTransaction(); 1958cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen } 1959cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen } 1960cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen } 1961cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen 1962cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen 19639299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen private MediaThumbRequest requestMediaThumbnail(String path, Uri uri, int priority, long magic) { 1964b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen synchronized (mMediaThumbQueue) { 1965e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen MediaThumbRequest req = null; 1966e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen try { 1967e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen req = new MediaThumbRequest( 19689299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen getContext().getContentResolver(), path, uri, priority, magic); 1969e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen mMediaThumbQueue.add(req); 1970e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen // Trigger the handler. 1971e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen Message msg = mThumbHandler.obtainMessage(IMAGE_THUMB); 1972e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen msg.sendToTarget(); 1973e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen } catch (Throwable t) { 1974e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen Log.w(TAG, t); 1975e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen } 1976b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return req; 1977b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1978b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1979b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1980702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private String generateFileName(boolean internal, String preferredExtension, String directoryName) 1981702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project { 1982702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // create a random file 1983702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String name = String.valueOf(System.currentTimeMillis()); 1984702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1985702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (internal) { 1986702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException("Writing to internal storage is not supported."); 1987702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project// return Environment.getDataDirectory() 1988702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project// + "/" + directoryName + "/" + name + preferredExtension; 1989702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 1990702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Environment.getExternalStorageDirectory() 1991702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project + "/" + directoryName + "/" + name + preferredExtension; 1992702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1993702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1994702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1995702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private boolean ensureFileExists(String path) { 1996702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File file = new File(path); 1997702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (file.exists()) { 1998702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return true; 1999702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 2000702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // we will not attempt to create the first directory in the path 2001702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // (for example, do not create /sdcard if the SD card is not mounted) 2002702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int secondSlash = path.indexOf('/', 1); 2003702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (secondSlash < 1) return false; 2004702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String directoryPath = path.substring(0, secondSlash); 2005702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File directory = new File(directoryPath); 2006702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!directory.exists()) 2007702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return false; 2008702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project file.getParentFile().mkdirs(); 2009702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 2010702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return file.createNewFile(); 2011702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } catch(IOException ioe) { 2012702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Log.e(TAG, "File creation failed", ioe); 2013702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2014702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return false; 2015702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2016702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2017702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2018702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final class GetTableAndWhereOutParameter { 2019702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public String table; 2020702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public String where; 2021702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2022702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2023702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project static final GetTableAndWhereOutParameter sGetTableAndWhereParam = 2024702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project new GetTableAndWhereOutParameter(); 2025702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2026702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private void getTableAndWhere(Uri uri, int match, String userWhere, 2027702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project GetTableAndWhereOutParameter out) { 2028702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String where = null; 2029702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (match) { 20309f02f449f6951b15bb9daaa3fc6e1d648b36b08aGoodwin case IMAGES_MEDIA: 20319f02f449f6951b15bb9daaa3fc6e1d648b36b08aGoodwin out.table = "images"; 20329f02f449f6951b15bb9daaa3fc6e1d648b36b08aGoodwin break; 20339f02f449f6951b15bb9daaa3fc6e1d648b36b08aGoodwin 2034702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA_ID: 2035702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "images"; 2036702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "_id = " + uri.getPathSegments().get(3); 2037702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2038702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2039b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case IMAGES_THUMBNAILS_ID: 2040b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen where = "_id=" + uri.getPathSegments().get(3); 2041b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case IMAGES_THUMBNAILS: 2042b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen out.table = "thumbnails"; 2043b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen break; 2044b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 2045702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA: 2046702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio"; 2047702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2048702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2049702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID: 2050702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio"; 2051702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "_id=" + uri.getPathSegments().get(3); 2052702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2053702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2054702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES: 2055702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_genres"; 2056702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "audio_id=" + uri.getPathSegments().get(3); 2057702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2058702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2059702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES_ID: 2060702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_genres"; 2061702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "audio_id=" + uri.getPathSegments().get(3) + 2062702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " AND genre_id=" + uri.getPathSegments().get(5); 2063702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2064702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2065702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS: 2066702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_playlists"; 2067702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "audio_id=" + uri.getPathSegments().get(3); 2068702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2069702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2070702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS_ID: 2071702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_playlists"; 2072702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "audio_id=" + uri.getPathSegments().get(3) + 2073702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " AND playlists_id=" + uri.getPathSegments().get(5); 2074702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2075702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2076702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES: 2077702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_genres"; 2078702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2079702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2080702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID: 2081702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_genres"; 2082702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "_id=" + uri.getPathSegments().get(3); 2083702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2084702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2085702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID_MEMBERS: 2086702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_genres"; 2087702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "genre_id=" + uri.getPathSegments().get(3); 2088702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2089702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2090702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID_MEMBERS_ID: 2091702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_genres"; 2092702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "genre_id=" + uri.getPathSegments().get(3) + 2093702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " AND audio_id =" + uri.getPathSegments().get(5); 2094702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2095702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2096702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS: 2097702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_playlists"; 2098702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2099702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2100702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID: 2101702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_playlists"; 2102702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "_id=" + uri.getPathSegments().get(3); 2103702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2104702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2105702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS: 2106702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_playlists_map"; 2107702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "playlist_id=" + uri.getPathSegments().get(3); 2108702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2109702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2110702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS_ID: 2111702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_playlists_map"; 2112702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "playlist_id=" + uri.getPathSegments().get(3) + 2113702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " AND _id=" + uri.getPathSegments().get(5); 2114702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2115702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2116702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ALBUMART_ID: 2117702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "album_art"; 2118702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "album_id=" + uri.getPathSegments().get(3); 2119702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2120702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2121702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA: 2122702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "video"; 2123702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2124702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2125702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA_ID: 2126702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "video"; 2127702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "_id=" + uri.getPathSegments().get(3); 2128702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2129702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2130b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case VIDEO_THUMBNAILS_ID: 2131b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen where = "_id=" + uri.getPathSegments().get(3); 2132b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case VIDEO_THUMBNAILS: 2133b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen out.table = "videothumbnails"; 2134b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen break; 2135b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 2136702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project default: 2137702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException( 2138702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Unknown or unsupported URL: " + uri.toString()); 2139702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2140702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2141702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Add in the user requested WHERE clause, if needed 2142702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!TextUtils.isEmpty(userWhere)) { 2143702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!TextUtils.isEmpty(where)) { 2144702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.where = where + " AND (" + userWhere + ")"; 2145702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 2146702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.where = userWhere; 2147702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2148702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 2149702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.where = where; 2150702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2151702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2152702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2153702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 2154702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public int delete(Uri uri, String userWhere, String[] whereArgs) { 2155702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int count; 2156702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int match = URI_MATCHER.match(uri); 2157702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2158702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // handle MEDIA_SCANNER before calling getDatabaseForUri() 2159702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (match == MEDIA_SCANNER) { 2160702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (mMediaScannerVolume == null) { 2161702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return 0; 2162702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2163702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mMediaScannerVolume = null; 2164702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return 1; 2165702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2166702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2167702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (match != VOLUMES_ID) { 2168702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DatabaseHelper database = getDatabaseForUri(uri); 2169702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (database == null) { 2170702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException( 2171702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Unknown URI: " + uri); 2172702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2173702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteDatabase db = database.getWritableDatabase(); 2174702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2175702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized (sGetTableAndWhereParam) { 2176702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getTableAndWhere(uri, match, userWhere, sGetTableAndWhereParam); 2177702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (match) { 2178702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA: 2179702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID: 2180702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count = db.delete("audio_meta", 2181702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sGetTableAndWhereParam.where, whereArgs); 2182702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2183702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project default: 2184702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count = db.delete(sGetTableAndWhereParam.table, 2185702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sGetTableAndWhereParam.where, whereArgs); 2186702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2187702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2188702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 2189702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2190702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 2191702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project detachVolume(uri); 2192702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count = 1; 2193702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2194702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2195702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return count; 2196702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2197702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2198702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 2199702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public int update(Uri uri, ContentValues initialValues, String userWhere, 2200702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String[] whereArgs) { 2201702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int count; 2202b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // Log.v(TAG, "update for uri="+uri+", initValues="+initialValues); 2203702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int match = URI_MATCHER.match(uri); 2204702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DatabaseHelper database = getDatabaseForUri(uri); 2205702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (database == null) { 2206702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException( 2207702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Unknown URI: " + uri); 2208702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2209702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteDatabase db = database.getWritableDatabase(); 2210702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2211702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized (sGetTableAndWhereParam) { 2212702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getTableAndWhere(uri, match, userWhere, sGetTableAndWhereParam); 2213702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2214702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (match) { 2215702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA: 2216702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID: 2217702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project { 2218702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(initialValues); 2219acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // TODO Remove this and actually store the album_artist in the 2220acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // database. For now this is here so the media scanner can start 2221acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // sending us the album_artist, even though it's not in the db yet. 2222acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen values.remove(MediaStore.Audio.Media.ALBUM_ARTIST); 222307656cccafca173c6ab54c681a69538dcf0516ddMarco Nelissen 2224702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Insert the artist into the artist table and remove it from 2225702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // the input values 2226a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen String artist = values.getAsString("artist"); 22276006570c27674c47fcea8e674832a715cfd653eaMarco Nelissen values.remove("artist"); 2228a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen if (artist != null) { 2229702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long artistRowId; 2230702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project HashMap<String, Long> artistCache = database.mArtistCache; 2231702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized(artistCache) { 2232a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen Long temp = artistCache.get(artist); 2233702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (temp == null) { 2234acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen artistRowId = getKeyIdForName(db, "artists", "artist_key", "artist", 2235acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen artist, artist, null, 0, null, artistCache, uri); 2236702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 2237702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project artistRowId = temp.longValue(); 2238702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2239702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2240702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put("artist_id", Integer.toString((int)artistRowId)); 2241702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2242702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 224359948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // Do the same for the album field. 2244a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen String so = values.getAsString("album"); 22456006570c27674c47fcea8e674832a715cfd653eaMarco Nelissen values.remove("album"); 2246702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (so != null) { 224759948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen String path = values.getAsString("_data"); 224859948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen int albumHash = 0; 224959948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen if (path == null) { 225059948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // If the path is null, we don't have a hash for the file in question. 225159948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen Log.w(TAG, "Update without specified path."); 225259948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen } else { 225359948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen albumHash = path.substring(0, path.lastIndexOf('/')).hashCode(); 225459948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen } 2255702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String s = so.toString(); 2256702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long albumRowId; 2257702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project HashMap<String, Long> albumCache = database.mAlbumCache; 2258702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized(albumCache) { 225959948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen String cacheName = s + albumHash; 226059948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen Long temp = albumCache.get(cacheName); 2261702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (temp == null) { 2262702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project albumRowId = getKeyIdForName(db, "albums", "album_key", "album", 2263a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen s, cacheName, path, albumHash, artist, albumCache, uri); 2264702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 2265702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project albumRowId = temp.longValue(); 2266702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2267702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2268702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put("album_id", Integer.toString((int)albumRowId)); 2269702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2270702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2271702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // don't allow the title_key field to be updated directly 2272702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.remove("title_key"); 2273702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // If the title field is modified, update the title_key 2274702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project so = values.getAsString("title"); 2275702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (so != null) { 2276702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String s = so.toString(); 2277702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put("title_key", MediaStore.Audio.keyFor(s)); 2278e96c1d9637e89b5f99c7002fd06f7f35a9164849Marco Nelissen // do a final trim of the title, in case it started with the special 2279e96c1d9637e89b5f99c7002fd06f7f35a9164849Marco Nelissen // "sort first" character (ascii \001) 2280e96c1d9637e89b5f99c7002fd06f7f35a9164849Marco Nelissen values.remove("title"); 2281e96c1d9637e89b5f99c7002fd06f7f35a9164849Marco Nelissen values.put("title", s.trim()); 2282702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2283702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2284702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count = db.update("audio_meta", values, sGetTableAndWhereParam.where, 2285702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project whereArgs); 2286702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2287702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2288702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA: 2289702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA_ID: 2290702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA: 2291702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA_ID: 2292702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project { 2293702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(initialValues); 2294702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Don't allow bucket id or display name to be updated directly. 2295702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // The same names are used for both images and table columns, so 2296702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // we use the ImageColumns constants here. 2297702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.remove(ImageColumns.BUCKET_ID); 2298702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.remove(ImageColumns.BUCKET_DISPLAY_NAME); 2299702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // If the data is being modified update the bucket values 2300702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String data = values.getAsString(MediaColumns.DATA); 2301702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (data != null) { 2302702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project computeBucketValues(data, values); 2303702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2304b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen computeTakenTime(values); 2305702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count = db.update(sGetTableAndWhereParam.table, values, 2306702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sGetTableAndWhereParam.where, whereArgs); 230701a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen // if this is a request from MediaScanner, DATA should contains file path 230801a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen // we only process update request from media scanner, otherwise the requests 230901a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen // could be duplicate. 231001a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen if (count > 0 && values.getAsString(MediaStore.MediaColumns.DATA) != null) { 231101a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen Cursor c = db.query(sGetTableAndWhereParam.table, 231201a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen READY_FLAG_PROJECTION, sGetTableAndWhereParam.where, 231301a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen whereArgs, null, null, null); 2314b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (c != null) { 2315216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen try { 2316216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen while (c.moveToNext()) { 2317216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen long magic = c.getLong(2); 2318216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen if (magic == 0) { 2319216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen requestMediaThumbnail(c.getString(1), uri, 2320216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen MediaThumbRequest.PRIORITY_NORMAL, 0); 2321216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen } 2322b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 2323216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen } finally { 2324216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen c.close(); 2325b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 2326b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 2327b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 2328702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2329702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2330f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen 2331f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen case AUDIO_PLAYLISTS_ID_MEMBERS_ID: 2332f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen String moveit = uri.getQueryParameter("move"); 2333f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen if (moveit != null) { 2334f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen String key = MediaStore.Audio.Playlists.Members.PLAY_ORDER; 2335f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen if (initialValues.containsKey(key)) { 2336f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen int newpos = initialValues.getAsInteger(key); 2337f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen List <String> segments = uri.getPathSegments(); 2338f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen long playlist = Long.valueOf(segments.get(3)); 2339f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen int oldpos = Integer.valueOf(segments.get(5)); 2340f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen return movePlaylistEntry(db, playlist, oldpos, newpos); 2341f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } 2342f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen throw new IllegalArgumentException("Need to specify " + key + 2343f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " when using 'move' parameter"); 2344f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } 2345f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen // fall through 2346702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project default: 2347702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count = db.update(sGetTableAndWhereParam.table, initialValues, 2348702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sGetTableAndWhereParam.where, whereArgs); 2349702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2350702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2351702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2352cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen // in a transaction, the code that began the transaction should be taking 2353cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen // care of notifications once it ends the transaction successfully 2354cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen if (count > 0 && !db.inTransaction()) { 2355702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 2356702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2357702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return count; 2358702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2359702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2360f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen private int movePlaylistEntry(SQLiteDatabase db, long playlist, int from, int to) { 2361f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen if (from == to) { 2362f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen return 0; 2363f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } 2364f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen db.beginTransaction(); 2365f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen try { 2366f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen int numlines = 0; 2367f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen db.execSQL("UPDATE audio_playlists_map SET play_order=-1" + 2368f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " WHERE play_order=" + from + 2369f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " AND playlist_id=" + playlist); 2370f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen // We could just run both of the next two statements, but only one of 2371f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen // of them will actually do anything, so might as well skip the compile 2372f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen // and execute steps. 2373f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen if (from < to) { 2374f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen db.execSQL("UPDATE audio_playlists_map SET play_order=play_order-1" + 2375f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " WHERE play_order<=" + to + " AND play_order>" + from + 2376f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " AND playlist_id=" + playlist); 2377f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen numlines = to - from + 1; 2378f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } else { 2379f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen db.execSQL("UPDATE audio_playlists_map SET play_order=play_order+1" + 2380f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " WHERE play_order>=" + to + " AND play_order<" + from + 2381f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " AND playlist_id=" + playlist); 2382f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen numlines = from - to + 1; 2383f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } 2384f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen db.execSQL("UPDATE audio_playlists_map SET play_order=" + to + 2385f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " WHERE play_order=-1 AND playlist_id=" + playlist); 2386f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen db.setTransactionSuccessful(); 2387f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen Uri uri = MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI 2388f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen .buildUpon().appendEncodedPath(String.valueOf(playlist)).build(); 2389f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen getContext().getContentResolver().notifyChange(uri, null); 2390f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen return numlines; 2391f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } finally { 2392f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen db.endTransaction(); 2393f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } 2394f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } 2395f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen 2396702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final String[] openFileColumns = new String[] { 2397702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.MediaColumns.DATA, 2398702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project }; 2399702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2400702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 2401702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public ParcelFileDescriptor openFile(Uri uri, String mode) 2402702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throws FileNotFoundException { 240371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen 2404702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ParcelFileDescriptor pfd = null; 240571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen 240671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (URI_MATCHER.match(uri) == AUDIO_ALBUMART_FILE_ID) { 240771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // get album art for the specified media file 240871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen DatabaseHelper database = getDatabaseForUri(uri); 240971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (database == null) { 241071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen throw new IllegalStateException("Couldn't open database for " + uri); 241171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 241271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen SQLiteDatabase db = database.getReadableDatabase(); 241371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 241471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen int songid = Integer.parseInt(uri.getPathSegments().get(3)); 241571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen qb.setTables("audio_meta"); 241671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen qb.appendWhere("_id=" + songid); 241771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen Cursor c = qb.query(db, 241871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen new String [] { 241971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen MediaStore.Audio.Media.DATA, 242071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen MediaStore.Audio.Media.ALBUM_ID }, 242171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen null, null, null, null, null); 242271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (c.moveToFirst()) { 242371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen String audiopath = c.getString(0); 242471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen int albumid = c.getInt(1); 242571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // Try to get existing album art for this album first, which 242671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // could possibly have been obtained from a different file. 242771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // If that fails, try to get it from this specific file. 242871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen Uri newUri = ContentUris.withAppendedId(ALBUMART_URI, albumid); 242971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen try { 243071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen pfd = openFile(newUri, mode); // recursive call 243171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } catch (FileNotFoundException ex) { 243271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // That didn't work, now try to get it from the specific file 243371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen pfd = getThumb(db, audiopath, albumid, null); 243471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 243571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 243671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen c.close(); 243771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen return pfd; 243871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 243971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen 2440702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 2441702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project pfd = openFileHelper(uri, mode); 2442702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } catch (FileNotFoundException ex) { 244371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (mode.contains("w")) { 244471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // if the file couldn't be created, we shouldn't extract album art 244571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen throw ex; 244671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 244771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen 2448702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (URI_MATCHER.match(uri) == AUDIO_ALBUMART_ID) { 2449702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Tried to open an album art file which does not exist. Regenerate. 2450702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DatabaseHelper database = getDatabaseForUri(uri); 2451702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (database == null) { 2452702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw ex; 2453702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2454702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteDatabase db = database.getReadableDatabase(); 2455702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 2456702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int albumid = Integer.parseInt(uri.getPathSegments().get(3)); 245771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen qb.setTables("audio_meta"); 2458702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("album_id=" + albumid); 2459702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Cursor c = qb.query(db, 2460702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project new String [] { 2461702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.Audio.Media.DATA }, 2462702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project null, null, null, null, null); 246371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (c.moveToFirst()) { 2464702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String audiopath = c.getString(0); 246571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen pfd = getThumb(db, audiopath, albumid, uri); 2466702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2467702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project c.close(); 2468702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 246971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (pfd == null) { 247071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen throw ex; 247171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 2472702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2473702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return pfd; 2474702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2475702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2476702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private class ThumbData { 2477702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteDatabase db; 2478702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String path; 2479702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long album_id; 2480702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Uri albumart_uri; 2481702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2482702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2483a9c4e330dacb37cfffa9c00f7da83cafde4accefMarco Nelissen private void makeThumbAsync(SQLiteDatabase db, String path, long album_id) { 24848a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber synchronized (mPendingThumbs) { 24858a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (mPendingThumbs.contains(path)) { 24868a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // There's already a request to make an album art thumbnail 24878a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // for this audio file in the queue. 24888a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber return; 24898a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 24908a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 24918a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber mPendingThumbs.add(path); 24928a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 24938a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 2494702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ThumbData d = new ThumbData(); 2495702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project d.db = db; 2496702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project d.path = path; 2497702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project d.album_id = album_id; 2498a9c4e330dacb37cfffa9c00f7da83cafde4accefMarco Nelissen d.albumart_uri = ContentUris.withAppendedId(mAlbumArtBaseUri, album_id); 24998a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 25008a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // Instead of processing thumbnail requests in the order they were 25018a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // received we instead process them stack-based, i.e. LIFO. 25028a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // The idea behind this is that the most recently requested thumbnails 25038a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // are most likely the ones still in the user's view, whereas those 25048a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // requested earlier may have already scrolled off. 25058a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber synchronized (mThumbRequestStack) { 25068a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber mThumbRequestStack.push(d); 25078a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 25088a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 25098a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // Trigger the handler. 2510b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen Message msg = mThumbHandler.obtainMessage(ALBUM_THUMB); 2511702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project msg.sendToTarget(); 2512702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2513702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 25148a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // Extract compressed image data from the audio file itself or, if that fails, 25158a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // look for a file "AlbumArt.jpg" in the containing directory. 25168a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber private static byte[] getCompressedAlbumArt(Context context, String path) { 25178a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber byte[] compressed = null; 2518702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2519702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 2520702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File f = new File(path); 2521702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ParcelFileDescriptor pfd = ParcelFileDescriptor.open(f, 2522702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ParcelFileDescriptor.MODE_READ_ONLY); 2523702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 25248a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber MediaScanner scanner = new MediaScanner(context); 25258a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber compressed = scanner.extractAlbumArt(pfd.getFileDescriptor()); 2526702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project pfd.close(); 2527702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2528d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // If no embedded art exists, look for a suitable image file in the 25293f9c37ea95a3bdf5f84dc79eb199256c4deda29aMarco Nelissen // same directory as the media file, except if that directory is 25303f9c37ea95a3bdf5f84dc79eb199256c4deda29aMarco Nelissen // is the root directory of the sd card or the download directory. 2531d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // We look for, in order of preference: 2532d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // 0 AlbumArt.jpg 2533d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // 1 AlbumArt*Large.jpg 2534d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // 2 Any other jpg image with 'albumart' anywhere in the name 2535d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // 3 Any other jpg image 2536d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // 4 any other png image 25378a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (compressed == null && path != null) { 2538702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int lastSlash = path.lastIndexOf('/'); 2539702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (lastSlash > 0) { 2540d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen 25413f9c37ea95a3bdf5f84dc79eb199256c4deda29aMarco Nelissen String artPath = path.substring(0, lastSlash); 25423f9c37ea95a3bdf5f84dc79eb199256c4deda29aMarco Nelissen String sdroot = Environment.getExternalStorageDirectory().getAbsolutePath(); 25430fe3097230b324e65a874bd7c8c0f430d2fb8cbeMarco Nelissen String dwndir = Environment.getExternalStoragePublicDirectory( 25442f07f572bc574b685b491ee07a6209c7f2dcb13fMarco Nelissen Environment.DIRECTORY_DOWNLOADS).getAbsolutePath(); 2545d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen 2546d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen String bestmatch = null; 2547d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen synchronized (sFolderArtMap) { 2548d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen if (sFolderArtMap.containsKey(artPath)) { 2549d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = sFolderArtMap.get(artPath); 2550ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen } else if (!artPath.equalsIgnoreCase(sdroot) && 2551ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen !artPath.equalsIgnoreCase(dwndir)) { 2552d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen File dir = new File(artPath); 2553d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen String [] entrynames = dir.list(); 2554d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen if (entrynames == null) { 2555d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen return null; 2556d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } 2557d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = null; 2558d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen int matchlevel = 1000; 2559d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen for (int i = entrynames.length - 1; i >=0; i--) { 2560d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen String entry = entrynames[i].toLowerCase(); 2561d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen if (entry.equals("albumart.jpg")) { 2562d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = entrynames[i]; 2563d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen break; 2564d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } else if (entry.startsWith("albumart") 2565d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen && entry.endsWith("large.jpg") 2566d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen && matchlevel > 1) { 2567d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = entrynames[i]; 2568d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen matchlevel = 1; 2569d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } else if (entry.contains("albumart") 2570d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen && entry.endsWith(".jpg") 2571d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen && matchlevel > 2) { 2572d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = entrynames[i]; 2573d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen matchlevel = 2; 2574d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } else if (entry.endsWith(".jpg") && matchlevel > 3) { 2575d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = entrynames[i]; 2576d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen matchlevel = 3; 2577d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } else if (entry.endsWith(".png") && matchlevel > 4) { 2578d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = entrynames[i]; 2579d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen matchlevel = 4; 2580d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } 2581d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } 2582d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // note that this may insert null if no album art was found 2583d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen sFolderArtMap.put(artPath, bestmatch); 2584d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } 2585d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } 2586d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen 2587d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen if (bestmatch != null) { 25883f9c37ea95a3bdf5f84dc79eb199256c4deda29aMarco Nelissen File file = new File(artPath, bestmatch); 2589d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen if (file.exists()) { 2590d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen compressed = new byte[(int)file.length()]; 2591d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen FileInputStream stream = null; 2592d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen try { 2593d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen stream = new FileInputStream(file); 2594d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen stream.read(compressed); 2595d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } catch (IOException ex) { 2596d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen compressed = null; 2597d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } finally { 2598d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen if (stream != null) { 2599d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen stream.close(); 2600d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } 2601702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2602702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2603702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2604702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2605702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 26068a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } catch (IOException e) { 26078a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 2608702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 26098a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber return compressed; 26108a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 2611702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 26128a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // Return a URI to write the album art to and update the database as necessary. 26138a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber Uri getAlbumArtOutputUri(SQLiteDatabase db, long album_id, Uri albumart_uri) { 26148a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber Uri out = null; 26158a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // TODO: this could be done more efficiently with a call to db.replace(), which 26168a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // replaces or inserts as needed, making it unnecessary to query() first. 26178a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (albumart_uri != null) { 26188a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber Cursor c = query(albumart_uri, new String [] { "_data" }, 26198a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber null, null, null); 262071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (c.moveToFirst()) { 26218a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber String albumart_path = c.getString(0); 26228a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (ensureFileExists(albumart_path)) { 26238a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber out = albumart_uri; 2624702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 262571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } else { 262671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen albumart_uri = null; 2627702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 26288a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber c.close(); 262971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 263071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (albumart_uri == null){ 26318a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber ContentValues initialValues = new ContentValues(); 26328a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber initialValues.put("album_id", album_id); 26338a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber try { 26348a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber ContentValues values = ensureFile(false, initialValues, "", ALBUM_THUMB_FOLDER); 26358a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber long rowId = db.insert("album_art", "_data", values); 26368a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (rowId > 0) { 26378a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber out = ContentUris.withAppendedId(ALBUMART_URI, rowId); 2638702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 26398a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } catch (IllegalStateException ex) { 26408a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber Log.e(TAG, "error creating album thumb file"); 26418a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 26428a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 26438a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber return out; 26448a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 26458a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 26468a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // Write out the album art to the output URI, recompresses the given Bitmap 26478a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // if necessary, otherwise writes the compressed data. 26488a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber private void writeAlbumArt( 26498a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber boolean need_to_recompress, Uri out, byte[] compressed, Bitmap bm) { 26508a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber boolean success = false; 26518a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber try { 26528a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber OutputStream outstream = getContext().getContentResolver().openOutputStream(out); 26538a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 26548a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (!need_to_recompress) { 26558a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // No need to recompress here, just write out the original 26568a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // compressed data here. 26578a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber outstream.write(compressed); 26588a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber success = true; 26598a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } else { 26608a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber success = bm.compress(Bitmap.CompressFormat.JPEG, 75, outstream); 2661702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 26628a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 26638a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber outstream.close(); 26648a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } catch (FileNotFoundException ex) { 26658a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber Log.e(TAG, "error creating file", ex); 2666702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } catch (IOException ex) { 26678a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber Log.e(TAG, "error creating file", ex); 26688a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 26698a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (!success) { 26708a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // the thumbnail was not written successfully, delete the entry that refers to it 26718a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber getContext().getContentResolver().delete(out, null, null); 2672702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 26738a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 26748a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 267571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen private ParcelFileDescriptor getThumb(SQLiteDatabase db, String path, long album_id, 267671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen Uri albumart_uri) { 267771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen ThumbData d = new ThumbData(); 267871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen d.db = db; 267971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen d.path = path; 268071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen d.album_id = album_id; 268171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen d.albumart_uri = albumart_uri; 268271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen return makeThumbInternal(d); 268371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 268471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen 268571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen private ParcelFileDescriptor makeThumbInternal(ThumbData d) { 26868a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber byte[] compressed = getCompressedAlbumArt(getContext(), d.path); 2687702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 26888a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (compressed == null) { 268971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen return null; 26908a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 26918a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 26928a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber Bitmap bm = null; 26938a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber boolean need_to_recompress = true; 26948a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 26958a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber try { 26968a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // get the size of the bitmap 26978a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber BitmapFactory.Options opts = new BitmapFactory.Options(); 26988a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.inJustDecodeBounds = true; 26998a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.inSampleSize = 1; 27008a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber BitmapFactory.decodeByteArray(compressed, 0, compressed.length, opts); 27018a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 27028a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // request a reasonably sized output image 27038a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // TODO: don't hardcode the size 27048a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber while (opts.outHeight > 320 || opts.outWidth > 320) { 27058a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.outHeight /= 2; 27068a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.outWidth /= 2; 27078a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.inSampleSize *= 2; 27088a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 27098a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 27108a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (opts.inSampleSize == 1) { 27118a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // The original album art was of proper size, we won't have to 27128a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // recompress the bitmap later. 27138a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber need_to_recompress = false; 27148a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } else { 27158a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // get the image for real now 27168a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.inJustDecodeBounds = false; 27178a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.inPreferredConfig = Bitmap.Config.RGB_565; 27188a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber bm = BitmapFactory.decodeByteArray(compressed, 0, compressed.length, opts); 27198a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 27208a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (bm != null && bm.getConfig() == null) { 2721a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen Bitmap nbm = bm.copy(Bitmap.Config.RGB_565, false); 2722a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen if (nbm != null && nbm != bm) { 2723a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen bm.recycle(); 2724a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen bm = nbm; 2725a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen } 27268a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 27278a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 27288a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } catch (Exception e) { 27298a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 27308a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 27318a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (need_to_recompress && bm == null) { 273271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen return null; 27338a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 27348a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 273571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (d.albumart_uri == null) { 273671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // this one doesn't need to be saved (probably a song with an unknown album), 273771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // so stick it in a memory file and return that 273871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen try { 273971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen MemoryFile file = new MemoryFile("albumthumb", compressed.length); 274071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen file.writeBytes(compressed, 0, 0, compressed.length); 274171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen file.deactivate(); 274271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen return file.getParcelFileDescriptor(); 274371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } catch (IOException e) { 274471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 274571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } else { 2746a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen // This one needs to actually be saved on the sd card. 2747a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen // This is wrapped in a transaction because there are various things 2748a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen // that could go wrong while generating the thumbnail, and we only want 2749a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen // to update the database when all steps succeeded. 2750a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen d.db.beginTransaction(); 2751a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen try { 2752a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen Uri out = getAlbumArtOutputUri(d.db, d.album_id, d.albumart_uri); 2753a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen 2754a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen if (out != null) { 2755a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen writeAlbumArt(need_to_recompress, out, compressed, bm); 2756a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen getContext().getContentResolver().notifyChange(MEDIA_URI, null); 2757a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen ParcelFileDescriptor pfd = openFileHelper(out, "r"); 2758a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen d.db.setTransactionSuccessful(); 2759a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen return pfd; 2760a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen } 2761a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen } catch (FileNotFoundException ex) { 2762a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen // do nothing, just return null below 2763a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen } catch (UnsupportedOperationException ex) { 2764a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen // do nothing, just return null below 2765a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen } finally { 2766a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen d.db.endTransaction(); 2767a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen if (bm != null) { 2768a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen bm.recycle(); 276971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 277071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 27718a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 277271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen return null; 2773702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2774702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2775702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 2776702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Look up the artist or album entry for the given name, creating that entry 2777702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * if it does not already exists. 2778702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param db The database 2779702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param table The table to store the key/name pair in. 2780702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param keyField The name of the key-column 2781702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param nameField The name of the name-column 2782702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param rawName The name that the calling app was trying to insert into the database 278359948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen * @param cacheName The string that will be inserted in to the cache 278459948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen * @param path The full path to the file being inserted in to the audio table 278559948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen * @param albumHash A hash to distinguish between different albums of the same name 2786a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen * @param artist The name of the artist, if known 2787702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param cache The cache to add this entry to 2788702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param srcuri The Uri that prompted the call to this method, used for determining whether this is 2789702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * the internal or external database 2790702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @return The row ID for this artist/album, or -1 if the provided name was invalid 2791702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 2792702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private long getKeyIdForName(SQLiteDatabase db, String table, String keyField, String nameField, 279359948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen String rawName, String cacheName, String path, int albumHash, 2794a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen String artist, HashMap<String, Long> cache, Uri srcuri) { 2795702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long rowId; 2796702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2797702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rawName == null || rawName.length() == 0) { 2798702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return -1; 2799702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2800702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String k = MediaStore.Audio.keyFor(rawName); 2801702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2802702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (k == null) { 2803702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return -1; 2804702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2805702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 280659948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen boolean isAlbum = table.equals("albums"); 2807e31cfb1a2c21e7ac7a646d40afbb48f49fab6907Marco Nelissen boolean isUnknown = MediaStore.UNKNOWN_STRING.equals(rawName); 280859948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen 280959948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // To distinguish same-named albums, we append a hash of the path. 281059948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // Ideally we would also take things like CDDB ID in to account, so 281159948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // we can group files from the same album that aren't in the same 281259948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // folder, but this is a quick and easy start that works immediately 281359948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // without requiring support from the mp3, mp4 and Ogg meta data 281459948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // readers, as long as the albums are in different folders. 2815a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen if (isAlbum) { 281659948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen k = k + albumHash; 2817a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen if (isUnknown) { 2818a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen k = k + artist; 2819a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen } 282059948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen } 282159948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen 2822702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String [] selargs = { k }; 2823702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Cursor c = db.query(table, null, keyField + "=?", selargs, null, null, null); 2824702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2825702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 2826702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (c.getCount()) { 2827702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case 0: { 2828702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // insert new entry into table 2829702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues otherValues = new ContentValues(); 2830702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project otherValues.put(keyField, k); 2831702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project otherValues.put(nameField, rawName); 2832702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert(table, "duration", otherValues); 283359948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen if (path != null && isAlbum && ! isUnknown) { 2834702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // We just inserted a new album. Now create an album art thumbnail for it. 2835a9c4e330dacb37cfffa9c00f7da83cafde4accefMarco Nelissen makeThumbAsync(db, path, rowId); 2836702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2837702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 2838702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String volume = srcuri.toString().substring(16, 24); // extract internal/external 2839702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Uri uri = Uri.parse("content://media/" + volume + "/audio/" + table + "/" + rowId); 2840702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 2841702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2842702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2843702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2844702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case 1: { 2845702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Use the existing entry 2846702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project c.moveToFirst(); 2847702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = c.getLong(0); 2848702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2849702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Determine whether the current rawName is better than what's 2850702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // currently stored in the table, and update the table if it is. 2851702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String currentFancyName = c.getString(2); 2852702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String bestName = makeBestName(rawName, currentFancyName); 2853702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!bestName.equals(currentFancyName)) { 2854702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // update the table with the new name 2855702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues newValues = new ContentValues(); 2856702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newValues.put(nameField, bestName); 2857702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.update(table, newValues, "rowid="+Integer.toString((int)rowId), null); 2858702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String volume = srcuri.toString().substring(16, 24); // extract internal/external 2859702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Uri uri = Uri.parse("content://media/" + volume + "/audio/" + table + "/" + rowId); 2860702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 2861702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2862702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2863702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2864702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project default: 2865702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // corrupt database 2866702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Log.e(TAG, "Multiple entries in table " + table + " for key " + k); 2867702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = -1; 2868702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2869702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2870702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 2871702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (c != null) c.close(); 2872702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2873702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 287459948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen if (cache != null && ! isUnknown) { 287559948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen cache.put(cacheName, rowId); 2876702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2877702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return rowId; 2878702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2879702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2880702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 2881702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Returns the best string to use for display, given two names. 2882702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Note that this function does not necessarily return either one 2883702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * of the provided names; it may decide to return a better alternative 2884702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * (for example, specifying the inputs "Police" and "Police, The" will 2885702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * return "The Police") 2886702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 2887702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * The basic assumptions are: 2888702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * - longer is better ("The police" is better than "Police") 2889702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * - prefix is better ("The Police" is better than "Police, The") 2890702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * - accents are better ("Motörhead" is better than "Motorhead") 2891702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 2892702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param one The first of the two names to consider 2893702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param two The last of the two names to consider 2894702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @return The actual name to use 2895702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 2896702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String makeBestName(String one, String two) { 2897702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String name; 2898702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2899702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Longer names are usually better. 2900702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (one.length() > two.length()) { 2901702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project name = one; 2902702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 2903702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Names with accents are usually better, and conveniently sort later 2904702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (one.toLowerCase().compareTo(two.toLowerCase()) > 0) { 2905702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project name = one; 2906702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 2907702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project name = two; 2908702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2909702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2910702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2911702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Prefixes are better than postfixes. 2912702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (name.endsWith(", the") || name.endsWith(",the") || 2913702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project name.endsWith(", an") || name.endsWith(",an") || 2914702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project name.endsWith(", a") || name.endsWith(",a")) { 2915702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String fix = name.substring(1 + name.lastIndexOf(',')); 2916702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project name = fix.trim() + " " + name.substring(0, name.lastIndexOf(',')); 2917702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2918702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2919702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // TODO: word-capitalize the resulting name 2920702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return name; 2921702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2922702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2923702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2924702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 2925702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Looks up the database based on the given URI. 2926702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 2927702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param uri The requested URI 2928702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @returns the database for the given URI 2929702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 2930702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private DatabaseHelper getDatabaseForUri(Uri uri) { 2931702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized (mDatabases) { 2932702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (uri.getPathSegments().size() > 1) { 2933702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return mDatabases.get(uri.getPathSegments().get(0)); 2934702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2935702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2936702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return null; 2937702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2938702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2939702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 2940702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Attach the database for a volume (internal or external). 2941702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Does nothing if the volume is already attached, otherwise 2942702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * checks the volume ID and sets up the corresponding database. 2943702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 2944702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param volume to attach, either {@link #INTERNAL_VOLUME} or {@link #EXTERNAL_VOLUME}. 2945702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @return the content URI of the attached volume. 2946702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 2947702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private Uri attachVolume(String volume) { 2948702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (Process.supportsProcesses() && Binder.getCallingPid() != Process.myPid()) { 2949702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new SecurityException( 2950702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Opening and closing databases not allowed."); 2951702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2952702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2953702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized (mDatabases) { 2954702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (mDatabases.get(volume) != null) { // Already attached 2955702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Uri.parse("content://media/" + volume); 2956702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2957702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2958702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DatabaseHelper db; 2959702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (INTERNAL_VOLUME.equals(volume)) { 2960702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db = new DatabaseHelper(getContext(), INTERNAL_DATABASE_NAME, true); 2961702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else if (EXTERNAL_VOLUME.equals(volume)) { 2962702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String path = Environment.getExternalStorageDirectory().getPath(); 2963702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int volumeID = FileUtils.getFatVolumeId(path); 2964702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (LOCAL_LOGV) Log.v(TAG, path + " volume ID: " + volumeID); 2965702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2966702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // generate database name based on volume ID 2967702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String dbName = "external-" + Integer.toHexString(volumeID) + ".db"; 2968702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db = new DatabaseHelper(getContext(), dbName, false); 29690027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen mVolumeId = volumeID; 2970702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 2971702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalArgumentException("There is no volume named " + volume); 2972702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2973702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2974702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mDatabases.put(volume, db); 2975702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2976702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!db.mInternal) { 2977702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // clean up stray album art files: delete every file not in the database 2978702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File[] files = new File( 2979702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Environment.getExternalStorageDirectory(), 2980702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ALBUM_THUMB_FOLDER).listFiles(); 2981702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project HashSet<String> fileSet = new HashSet(); 2982702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project for (int i = 0; files != null && i < files.length; i++) { 2983702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project fileSet.add(files[i].getPath()); 2984702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2985702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2986702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Cursor cursor = query(MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI, 2987702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project new String[] { MediaStore.Audio.Albums.ALBUM_ART }, null, null, null); 2988702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 2989702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project while (cursor != null && cursor.moveToNext()) { 2990702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project fileSet.remove(cursor.getString(0)); 2991702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2992702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 2993702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (cursor != null) cursor.close(); 2994702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2995702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2996702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Iterator<String> iterator = fileSet.iterator(); 2997702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project while (iterator.hasNext()) { 2998702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String filename = iterator.next(); 2999702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (LOCAL_LOGV) Log.v(TAG, "deleting obsolete album art " + filename); 3000702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project new File(filename).delete(); 3001702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3002702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3003702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3004702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3005702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (LOCAL_LOGV) Log.v(TAG, "Attached volume: " + volume); 3006702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Uri.parse("content://media/" + volume); 3007702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3008702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3009702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 3010702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Detach the database for a volume (must be external). 3011702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Does nothing if the volume is already detached, otherwise 3012702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * closes the database and sends a notification to listeners. 3013702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 3014702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param uri The content URI of the volume, as returned by {@link #attachVolume} 3015702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 3016702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private void detachVolume(Uri uri) { 3017702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (Process.supportsProcesses() && Binder.getCallingPid() != Process.myPid()) { 3018702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new SecurityException( 3019702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Opening and closing databases not allowed."); 3020702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3021702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3022702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String volume = uri.getPathSegments().get(0); 3023702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (INTERNAL_VOLUME.equals(volume)) { 3024702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException( 3025702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Deleting the internal volume is not allowed"); 3026702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else if (!EXTERNAL_VOLUME.equals(volume)) { 3027702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalArgumentException( 3028702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "There is no volume named " + volume); 3029702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3030702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3031702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized (mDatabases) { 3032702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DatabaseHelper database = mDatabases.get(volume); 3033702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (database == null) return; 3034702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3035702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 3036702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // touch the database file to show it is most recently used 3037702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File file = new File(database.getReadableDatabase().getPath()); 3038702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project file.setLastModified(System.currentTimeMillis()); 3039702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } catch (SQLException e) { 3040702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Log.e(TAG, "Can't touch database file", e); 3041702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3042702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3043702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mDatabases.remove(volume); 3044702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project database.close(); 3045702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3046702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3047702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 3048702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (LOCAL_LOGV) Log.v(TAG, "Detached volume: " + volume); 3049702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3050702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3051702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static String TAG = "MediaProvider"; 3052702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final boolean LOCAL_LOGV = true; 3053022eb71bfe8ec65b8817eaa432a530194210ec23Marco Nelissen private static final int DATABASE_VERSION = 90; 3054702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final String INTERNAL_DATABASE_NAME = "internal.db"; 3055702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3056702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // maximum number of cached external databases to keep 3057702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int MAX_EXTERNAL_DATABASES = 3; 3058702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3059702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Delete databases that have not been used in two months 3060702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // 60 days in milliseconds (1000 * 60 * 60 * 24 * 60) 3061702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final long OBSOLETE_DATABASE_DB = 5184000000L; 3062702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3063702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private HashMap<String, DatabaseHelper> mDatabases; 3064702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3065702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private Handler mThumbHandler; 3066702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3067702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // name of the volume currently being scanned by the media scanner (or null) 3068702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private String mMediaScannerVolume; 3069702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 30700027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen // current FAT volume ID 30710027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen private int mVolumeId; 30720027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen 3073702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project static final String INTERNAL_VOLUME = "internal"; 3074702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project static final String EXTERNAL_VOLUME = "external"; 3075268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen static final String ALBUM_THUMB_FOLDER = "Android/data/com.android.providers.media/albumthumbs"; 3076702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3077702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // path for writing contents of in memory temp database 3078702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private String mTempDatabasePath; 3079702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3080702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int IMAGES_MEDIA = 1; 3081702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int IMAGES_MEDIA_ID = 2; 3082702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int IMAGES_THUMBNAILS = 3; 3083702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int IMAGES_THUMBNAILS_ID = 4; 3084702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3085702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_MEDIA = 100; 3086702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_MEDIA_ID = 101; 3087702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_MEDIA_ID_GENRES = 102; 3088702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_MEDIA_ID_GENRES_ID = 103; 3089702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_MEDIA_ID_PLAYLISTS = 104; 3090702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_MEDIA_ID_PLAYLISTS_ID = 105; 3091702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_GENRES = 106; 3092702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_GENRES_ID = 107; 3093702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_GENRES_ID_MEMBERS = 108; 3094702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_GENRES_ID_MEMBERS_ID = 109; 3095702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_PLAYLISTS = 110; 3096702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_PLAYLISTS_ID = 111; 3097702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_PLAYLISTS_ID_MEMBERS = 112; 3098702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_PLAYLISTS_ID_MEMBERS_ID = 113; 3099702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ARTISTS = 114; 3100702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ARTISTS_ID = 115; 3101702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ALBUMS = 116; 3102702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ALBUMS_ID = 117; 3103702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ARTISTS_ID_ALBUMS = 118; 3104702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ALBUMART = 119; 3105702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ALBUMART_ID = 120; 310671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen private static final int AUDIO_ALBUMART_FILE_ID = 121; 3107702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3108702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int VIDEO_MEDIA = 200; 3109702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int VIDEO_MEDIA_ID = 201; 3110b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private static final int VIDEO_THUMBNAILS = 202; 3111b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private static final int VIDEO_THUMBNAILS_ID = 203; 3112702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3113702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int VOLUMES = 300; 3114702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int VOLUMES_ID = 301; 3115702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3116a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen private static final int AUDIO_SEARCH_LEGACY = 400; 3117a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen private static final int AUDIO_SEARCH_BASIC = 401; 3118a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen private static final int AUDIO_SEARCH_FANCY = 402; 3119702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3120702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int MEDIA_SCANNER = 500; 3121702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 31220027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen private static final int FS_ID = 600; 31230027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen 3124702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final UriMatcher URI_MATCHER = 3125702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project new UriMatcher(UriMatcher.NO_MATCH); 3126702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3127b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private static final String[] ID_PROJECTION = new String[] { 3128b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen MediaStore.MediaColumns._ID 3129b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen }; 3130b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 3131702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final String[] MIME_TYPE_PROJECTION = new String[] { 3132702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.MediaColumns._ID, // 0 3133702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.MediaColumns.MIME_TYPE, // 1 3134702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project }; 3135702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3136b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private static final String[] READY_FLAG_PROJECTION = new String[] { 3137b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen MediaStore.MediaColumns._ID, 3138b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen MediaStore.MediaColumns.DATA, 3139b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen Images.Media.MINI_THUMB_MAGIC 3140b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen }; 3141b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 3142702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final String[] EXTERNAL_DATABASE_TABLES = new String[] { 3143702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "images", 3144702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "thumbnails", 3145702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_meta", 3146702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "artists", 3147702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "albums", 3148702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_genres", 3149702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_genres_map", 3150702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_playlists", 3151702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_playlists_map", 3152702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "video", 3153702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project }; 3154702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3155702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project static 3156702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project { 3157702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/images/media", IMAGES_MEDIA); 3158702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/images/media/#", IMAGES_MEDIA_ID); 3159702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/images/thumbnails", IMAGES_THUMBNAILS); 3160702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/images/thumbnails/#", IMAGES_THUMBNAILS_ID); 3161702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3162702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/media", AUDIO_MEDIA); 3163702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/media/#", AUDIO_MEDIA_ID); 3164702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/media/#/genres", AUDIO_MEDIA_ID_GENRES); 3165702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/media/#/genres/#", AUDIO_MEDIA_ID_GENRES_ID); 3166702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/media/#/playlists", AUDIO_MEDIA_ID_PLAYLISTS); 3167702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/media/#/playlists/#", AUDIO_MEDIA_ID_PLAYLISTS_ID); 3168702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/genres", AUDIO_GENRES); 3169702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/genres/#", AUDIO_GENRES_ID); 3170702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/genres/#/members", AUDIO_GENRES_ID_MEMBERS); 3171702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/genres/#/members/#", AUDIO_GENRES_ID_MEMBERS_ID); 3172702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/playlists", AUDIO_PLAYLISTS); 3173702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/playlists/#", AUDIO_PLAYLISTS_ID); 3174702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/playlists/#/members", AUDIO_PLAYLISTS_ID_MEMBERS); 3175702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/playlists/#/members/#", AUDIO_PLAYLISTS_ID_MEMBERS_ID); 3176702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/artists", AUDIO_ARTISTS); 3177702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/artists/#", AUDIO_ARTISTS_ID); 3178702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/artists/#/albums", AUDIO_ARTISTS_ID_ALBUMS); 3179702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/albums", AUDIO_ALBUMS); 3180702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/albums/#", AUDIO_ALBUMS_ID); 3181702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/albumart", AUDIO_ALBUMART); 3182702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/albumart/#", AUDIO_ALBUMART_ID); 318371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen URI_MATCHER.addURI("media", "*/audio/media/#/albumart", AUDIO_ALBUMART_FILE_ID); 3184702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3185702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/video/media", VIDEO_MEDIA); 3186702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/video/media/#", VIDEO_MEDIA_ID); 3187b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen URI_MATCHER.addURI("media", "*/video/thumbnails", VIDEO_THUMBNAILS); 3188b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen URI_MATCHER.addURI("media", "*/video/thumbnails/#", VIDEO_THUMBNAILS_ID); 3189702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3190702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/media_scanner", MEDIA_SCANNER); 3191702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 31920027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen URI_MATCHER.addURI("media", "*/fs_id", FS_ID); 31930027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen 3194702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*", VOLUMES_ID); 3195702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", null, VOLUMES); 3196702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3197a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen /** 3198a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen * @deprecated use the 'basic' or 'fancy' search Uris instead 3199a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen */ 3200702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/" + SearchManager.SUGGEST_URI_PATH_QUERY, 3201a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen AUDIO_SEARCH_LEGACY); 3202702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/" + SearchManager.SUGGEST_URI_PATH_QUERY + "/*", 3203a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen AUDIO_SEARCH_LEGACY); 3204a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen 3205a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // used for search suggestions 3206a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen URI_MATCHER.addURI("media", "*/audio/search/" + SearchManager.SUGGEST_URI_PATH_QUERY, 3207a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen AUDIO_SEARCH_BASIC); 3208a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen URI_MATCHER.addURI("media", "*/audio/search/" + SearchManager.SUGGEST_URI_PATH_QUERY + 3209a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "/*", AUDIO_SEARCH_BASIC); 3210a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen 3211a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // used by the music app's search activity 3212a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen URI_MATCHER.addURI("media", "*/audio/search/fancy", AUDIO_SEARCH_FANCY); 3213a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen URI_MATCHER.addURI("media", "*/audio/search/fancy/*", AUDIO_SEARCH_FANCY); 3214702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3215702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project} 3216