MediaProvider.java revision 9ea338b3f2720a16a334990bf2bb6afc5011b60e
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; 31b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwoodimport android.media.MediaFile; 32702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.media.MediaScanner; 33b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chenimport android.media.MiniThumbFile; 34702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.net.Uri; 35702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.Binder; 36702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.Environment; 37702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.FileUtils; 38702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.Handler; 39ab43e1853533e4d9352c251d53c36fb645077e43Chih-Chung Changimport android.os.HandlerThread; 40702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.Looper; 4171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissenimport android.os.MemoryFile; 42702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.Message; 43702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.ParcelFileDescriptor; 44702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.os.Process; 45702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.BaseColumns; 46702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.MediaStore; 47702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.MediaStore.Audio; 48702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.MediaStore.Images; 49702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.MediaStore.MediaColumns; 50702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.MediaStore.Video; 51702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.provider.MediaStore.Images.ImageColumns; 52b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwoodimport android.provider.MediaStore.MtpObjects; 53b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwoodimport android.provider.MediaStore.MtpObjects.ObjectColumns; 54b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwoodimport android.provider.Mtp; 55702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.text.TextUtils; 56702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport android.util.Log; 57702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 58702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.io.File; 59702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.io.FileInputStream; 60702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.io.FileNotFoundException; 61702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.io.IOException; 62702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.io.OutputStream; 63702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.text.Collator; 64cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissenimport java.util.ArrayList; 65702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.util.HashMap; 66702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.util.HashSet; 67702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectimport java.util.Iterator; 68f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissenimport java.util.List; 69b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chenimport java.util.PriorityQueue; 708a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huberimport java.util.Stack; 71702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 72702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project/** 73702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Media content provider. See {@link android.provider.MediaStore} for details. 74702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Separate databases are kept for each external storage card we see (using the 75702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * card's ID as an index). The content visible at content://media/external/... 76702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * changes with the card. 77702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 78702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Projectpublic class MediaProvider extends ContentProvider { 79702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final Uri MEDIA_URI = Uri.parse("content://media"); 80702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final Uri ALBUMART_URI = Uri.parse("content://media/external/audio/albumart"); 81b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private static final int ALBUM_THUMB = 1; 82b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private static final int IMAGE_THUMB = 2; 83702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 84702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final HashMap<String, String> sArtistAlbumsMap = new HashMap<String, String>(); 85d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen private static final HashMap<String, String> sFolderArtMap = new HashMap<String, String>(); 86702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 878a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // A HashSet of paths that are pending creation of album art thumbnails. 888a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber private HashSet mPendingThumbs = new HashSet(); 898a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 908a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // A Stack of outstanding thumbnail requests. 918a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber private Stack mThumbRequestStack = new Stack(); 928a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 9320434e032e498b716f87cce2f23dd646819218bfRay Chen // The lock of mMediaThumbQueue protects both mMediaThumbQueue and mCurrentThumbRequest. 9420434e032e498b716f87cce2f23dd646819218bfRay Chen private MediaThumbRequest mCurrentThumbRequest = null; 95b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private PriorityQueue<MediaThumbRequest> mMediaThumbQueue = 96b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen new PriorityQueue<MediaThumbRequest>(MediaThumbRequest.PRIORITY_NORMAL, 97b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen MediaThumbRequest.getComparator()); 98b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 99a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // For compatibility with the approximately 0 apps that used mediaprovider search in 100a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // releases 1.0, 1.1 or 1.5 101a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen private String[] mSearchColsLegacy = new String[] { 102a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen android.provider.BaseColumns._ID, 103a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen MediaStore.Audio.Media.MIME_TYPE, 104a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "(CASE WHEN grouporder=1 THEN " + R.drawable.ic_search_category_music_artist + 105a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen " ELSE CASE WHEN grouporder=2 THEN " + R.drawable.ic_search_category_music_album + 106a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen " ELSE " + R.drawable.ic_search_category_music_song + " END END" + 107a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen ") AS " + SearchManager.SUGGEST_COLUMN_ICON_1, 108a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "0 AS " + SearchManager.SUGGEST_COLUMN_ICON_2, 109a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "text1 AS " + SearchManager.SUGGEST_COLUMN_TEXT_1, 110a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "text1 AS " + SearchManager.SUGGEST_COLUMN_QUERY, 111a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "CASE when grouporder=1 THEN data1 ELSE artist END AS data1", 112a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "CASE when grouporder=1 THEN data2 ELSE " + 113a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "CASE WHEN grouporder=2 THEN NULL ELSE album END END AS data2", 114a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "match as ar", 115a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen SearchManager.SUGGEST_COLUMN_INTENT_DATA, 116a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "grouporder", 117ea74c8add2d5b4215dfeb69183632d9e9797ac5aMarco Nelissen "NULL AS itemorder" // We should be sorting by the artist/album/title keys, but that 118ea74c8add2d5b4215dfeb69183632d9e9797ac5aMarco Nelissen // column is not available here, and the list is already sorted. 119a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen }; 120a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen private String[] mSearchColsFancy = new String[] { 121a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen android.provider.BaseColumns._ID, 122a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen MediaStore.Audio.Media.MIME_TYPE, 123a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen MediaStore.Audio.Artists.ARTIST, 124a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen MediaStore.Audio.Albums.ALBUM, 125a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen MediaStore.Audio.Media.TITLE, 126a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "data1", 127a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "data2", 128a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen }; 12963f748ff8b258d9110038778a006b3000164fbeeSatish Sampath // If this array gets changed, please update the constant below to point to the correct item. 130a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen private String[] mSearchColsBasic = new String[] { 131a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen android.provider.BaseColumns._ID, 132a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen MediaStore.Audio.Media.MIME_TYPE, 133a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "(CASE WHEN grouporder=1 THEN " + R.drawable.ic_search_category_music_artist + 134a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen " ELSE CASE WHEN grouporder=2 THEN " + R.drawable.ic_search_category_music_album + 135a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen " ELSE " + R.drawable.ic_search_category_music_song + " END END" + 136a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen ") AS " + SearchManager.SUGGEST_COLUMN_ICON_1, 137a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "text1 AS " + SearchManager.SUGGEST_COLUMN_TEXT_1, 138a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "text1 AS " + SearchManager.SUGGEST_COLUMN_QUERY, 13963f748ff8b258d9110038778a006b3000164fbeeSatish Sampath "(CASE WHEN grouporder=1 THEN '%1'" + // %1 gets replaced with localized string. 14063f748ff8b258d9110038778a006b3000164fbeeSatish Sampath " ELSE CASE WHEN grouporder=3 THEN artist || ' - ' || album" + 141e31cfb1a2c21e7ac7a646d40afbb48f49fab6907Marco Nelissen " ELSE CASE WHEN text2!='" + MediaStore.UNKNOWN_STRING + "' THEN text2" + 14263f748ff8b258d9110038778a006b3000164fbeeSatish Sampath " ELSE NULL END END END) AS " + SearchManager.SUGGEST_COLUMN_TEXT_2, 143a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen SearchManager.SUGGEST_COLUMN_INTENT_DATA 144a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen }; 14563f748ff8b258d9110038778a006b3000164fbeeSatish Sampath // Position of the TEXT_2 item in the above array. 14663f748ff8b258d9110038778a006b3000164fbeeSatish Sampath private final int SEARCH_COLUMN_BASIC_TEXT2 = 5; 147a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen 1481717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood private static final String[] mMediaTableColumns = new String[] { 1491717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood ObjectColumns._ID, 1501717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood ObjectColumns.MEDIA_TABLE, 1511717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood ObjectColumns.MEDIA_ID, 1521717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood }; 1531717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood 154a9c4e330dacb37cfffa9c00f7da83cafde4accefMarco Nelissen private Uri mAlbumArtBaseUri = Uri.parse("content://media/external/audio/albumart"); 155a9c4e330dacb37cfffa9c00f7da83cafde4accefMarco Nelissen 156702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private BroadcastReceiver mUnmountReceiver = new BroadcastReceiver() { 157702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 158702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public void onReceive(Context context, Intent intent) { 159702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (intent.getAction().equals(Intent.ACTION_MEDIA_EJECT)) { 160702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Remove the external volume and then notify all cursors backed by 161702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // data on that volume 162702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project detachVolume(Uri.parse("content://media/external")); 163d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen sFolderArtMap.clear(); 164b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen MiniThumbFile.reset(); 165702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 166702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 167702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project }; 168702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 169702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 170702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Wrapper class for a specific database (associated with one particular 171702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * external card, or with internal storage). Can open the actual database 172702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * on demand, create and upgrade the schema, etc. 173702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 174702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final class DatabaseHelper extends SQLiteOpenHelper { 175702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final Context mContext; 176702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final boolean mInternal; // True if this is the internal database 177702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 178702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // In memory caches of artist and album data. 179702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project HashMap<String, Long> mArtistCache = new HashMap<String, Long>(); 180702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project HashMap<String, Long> mAlbumCache = new HashMap<String, Long>(); 181702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 182702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public DatabaseHelper(Context context, String name, boolean internal) { 183702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project super(context, name, null, DATABASE_VERSION); 184702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mContext = context; 185702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mInternal = internal; 186702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 187702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 188702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 189702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Creates database the first time we try to open it. 190702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 191702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 192702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public void onCreate(final SQLiteDatabase db) { 193702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project updateDatabase(db, mInternal, 0, DATABASE_VERSION); 194702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 195702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 196702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 197702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Updates the database format when a new content provider is used 198702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * with an older database format. 199702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 200702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 201702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public void onUpgrade(final SQLiteDatabase db, final int oldV, final int newV) { 202702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project updateDatabase(db, mInternal, oldV, newV); 203702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 204702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 205702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 206702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Touch this particular database and garbage collect old databases. 207702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * An LRU cache system is used to clean up databases for old external 208702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * storage volumes. 209702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 210702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 211702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public void onOpen(SQLiteDatabase db) { 212702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (mInternal) return; // The internal database is kept separately. 213702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 214702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // touch the database file to show it is most recently used 215702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File file = new File(db.getPath()); 216702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long now = System.currentTimeMillis(); 217702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project file.setLastModified(now); 218702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 219702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // delete least recently used databases if we are over the limit 220702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String[] databases = mContext.databaseList(); 221702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int count = databases.length; 222702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int limit = MAX_EXTERNAL_DATABASES; 223702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 224702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // delete external databases that have not been used in the past two months 225702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long twoMonthsAgo = now - OBSOLETE_DATABASE_DB; 226702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project for (int i = 0; i < databases.length; i++) { 227702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File other = mContext.getDatabasePath(databases[i]); 228702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (INTERNAL_DATABASE_NAME.equals(databases[i]) || file.equals(other)) { 229702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project databases[i] = null; 230702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count--; 231702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (file.equals(other)) { 232702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // reduce limit to account for the existence of the database we 233702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // are about to open, which we removed from the list. 234702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project limit--; 235702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 236702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 237702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long time = other.lastModified(); 238702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (time < twoMonthsAgo) { 239702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (LOCAL_LOGV) Log.v(TAG, "Deleting old database " + databases[i]); 240702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mContext.deleteDatabase(databases[i]); 241702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project databases[i] = null; 242702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count--; 243702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 244702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 245702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 246702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 247702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // delete least recently used databases until 248702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // we are no longer over the limit 249702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project while (count > limit) { 250702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int lruIndex = -1; 251702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long lruTime = 0; 252702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 253702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project for (int i = 0; i < databases.length; i++) { 254702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (databases[i] != null) { 255702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long time = mContext.getDatabasePath(databases[i]).lastModified(); 256702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (lruTime == 0 || time < lruTime) { 257702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project lruIndex = i; 258702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project lruTime = time; 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 // delete least recently used database 264702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (lruIndex != -1) { 265702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (LOCAL_LOGV) Log.v(TAG, "Deleting old database " + databases[lruIndex]); 266702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mContext.deleteDatabase(databases[lruIndex]); 267702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project databases[lruIndex] = null; 268702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count--; 269702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 270702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 271702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 272702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 273702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 274702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 275702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public boolean onCreate() { 276acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen sArtistAlbumsMap.put(MediaStore.Audio.Albums._ID, "audio.album_id AS " + 277acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen MediaStore.Audio.Albums._ID); 278702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Albums.ALBUM, "album"); 279702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Albums.ALBUM_KEY, "album_key"); 280acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen sArtistAlbumsMap.put(MediaStore.Audio.Albums.FIRST_YEAR, "MIN(year) AS " + 281702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.Audio.Albums.FIRST_YEAR); 282acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen sArtistAlbumsMap.put(MediaStore.Audio.Albums.LAST_YEAR, "MAX(year) AS " + 283702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.Audio.Albums.LAST_YEAR); 284702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Media.ARTIST, "artist"); 285702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Media.ARTIST_ID, "artist"); 286702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Media.ARTIST_KEY, "artist_key"); 287acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen sArtistAlbumsMap.put(MediaStore.Audio.Albums.NUMBER_OF_SONGS, "count(*) AS " + 288acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen MediaStore.Audio.Albums.NUMBER_OF_SONGS); 289acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen sArtistAlbumsMap.put(MediaStore.Audio.Albums.ALBUM_ART, "album_art._data AS " + 290acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen MediaStore.Audio.Albums.ALBUM_ART); 291702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 29263f748ff8b258d9110038778a006b3000164fbeeSatish Sampath mSearchColsBasic[SEARCH_COLUMN_BASIC_TEXT2] = 29363f748ff8b258d9110038778a006b3000164fbeeSatish Sampath mSearchColsBasic[SEARCH_COLUMN_BASIC_TEXT2].replaceAll( 29463f748ff8b258d9110038778a006b3000164fbeeSatish Sampath "%1", getContext().getString(R.string.artist_label)); 295702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mDatabases = new HashMap<String, DatabaseHelper>(); 296702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project attachVolume(INTERNAL_VOLUME); 297702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 298702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project IntentFilter iFilter = new IntentFilter(Intent.ACTION_MEDIA_EJECT); 299702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project iFilter.addDataScheme("file"); 300702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().registerReceiver(mUnmountReceiver, iFilter); 301702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 302702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // open external database if external storage is mounted 303702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String state = Environment.getExternalStorageState(); 304702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (Environment.MEDIA_MOUNTED.equals(state) || 305702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) { 306702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project attachVolume(EXTERNAL_VOLUME); 307702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 308702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 309ab43e1853533e4d9352c251d53c36fb645077e43Chih-Chung Chang HandlerThread ht = new HandlerThread("thumbs thread", Process.THREAD_PRIORITY_BACKGROUND); 310ab43e1853533e4d9352c251d53c36fb645077e43Chih-Chung Chang ht.start(); 311ab43e1853533e4d9352c251d53c36fb645077e43Chih-Chung Chang mThumbHandler = new Handler(ht.getLooper()) { 312702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 313702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public void handleMessage(Message msg) { 314b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (msg.what == IMAGE_THUMB) { 315b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen synchronized (mMediaThumbQueue) { 31620434e032e498b716f87cce2f23dd646819218bfRay Chen mCurrentThumbRequest = mMediaThumbQueue.poll(); 317b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 31820434e032e498b716f87cce2f23dd646819218bfRay Chen if (mCurrentThumbRequest == null) { 319b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen Log.w(TAG, "Have message but no request?"); 320b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } else { 321b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen try { 32220434e032e498b716f87cce2f23dd646819218bfRay Chen File origFile = new File(mCurrentThumbRequest.mPath); 3234d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen if (origFile.exists() && origFile.length() > 0) { 32420434e032e498b716f87cce2f23dd646819218bfRay Chen mCurrentThumbRequest.execute(); 3254d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen } else { 3264d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen // original file hasn't been stored yet 3274d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen synchronized (mMediaThumbQueue) { 32820434e032e498b716f87cce2f23dd646819218bfRay Chen Log.w(TAG, "original file hasn't been stored yet: " + mCurrentThumbRequest.mPath); 3294d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen } 3304d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen } 331b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } catch (IOException ex) { 3321d6eba9e1e28c722aa73a651d86a2efe2b937bf2Ray Chen Log.w(TAG, ex); 3331d6eba9e1e28c722aa73a651d86a2efe2b937bf2Ray Chen } catch (UnsupportedOperationException ex) { 3341d6eba9e1e28c722aa73a651d86a2efe2b937bf2Ray Chen // This could happen if we unplug the sd card during insert/update/delete 3351d6eba9e1e28c722aa73a651d86a2efe2b937bf2Ray Chen // See getDatabaseForUri. 3361d6eba9e1e28c722aa73a651d86a2efe2b937bf2Ray Chen Log.w(TAG, ex); 337b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } finally { 33820434e032e498b716f87cce2f23dd646819218bfRay Chen synchronized (mCurrentThumbRequest) { 33920434e032e498b716f87cce2f23dd646819218bfRay Chen mCurrentThumbRequest.mState = MediaThumbRequest.State.DONE; 34020434e032e498b716f87cce2f23dd646819218bfRay Chen mCurrentThumbRequest.notifyAll(); 341b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 342b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 343b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 344b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } else if (msg.what == ALBUM_THUMB) { 345b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen ThumbData d; 346b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen synchronized (mThumbRequestStack) { 347b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen d = (ThumbData)mThumbRequestStack.pop(); 348b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 3498a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 350b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen makeThumbInternal(d); 351b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen synchronized (mPendingThumbs) { 352b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen mPendingThumbs.remove(d.path); 353b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 3548a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 355702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 356702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project }; 357702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 358702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return true; 359702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 360702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 361702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 362702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * This method takes care of updating all the tables in the database to the 363702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * current version, creating them if necessary. 364702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * This method can only update databases at schema 63 or higher, which was 365702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * created August 1, 2008. Older database will be cleared and recreated. 366702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param db Database 367702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param internal True if this is the internal media database 368702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 369702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static void updateDatabase(SQLiteDatabase db, boolean internal, 370702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int fromVersion, int toVersion) { 371702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 372702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // sanity checks 373702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (toVersion != DATABASE_VERSION) { 374702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Log.e(TAG, "Illegal update request. Got " + toVersion + ", expected " + 375702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DATABASE_VERSION); 376702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalArgumentException(); 377702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else if (fromVersion > toVersion) { 37895ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen Log.e(TAG, "Illegal update request: can't downgrade from " + fromVersion + 379702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " to " + toVersion + ". Did you forget to wipe data?"); 380702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalArgumentException(); 381702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 382702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 383acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // Revisions 84-86 were a failed attempt at supporting the "album artist" id3 tag 384acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // We can't downgrade from those revisions, so start over. 385022eb71bfe8ec65b8817eaa432a530194210ec23Marco Nelissen // (the initial change to do this was wrong, so now we actually need to start over 386022eb71bfe8ec65b8817eaa432a530194210ec23Marco Nelissen // if the database version is 84-89) 387022eb71bfe8ec65b8817eaa432a530194210ec23Marco Nelissen if (fromVersion < 63 || (fromVersion >= 84 && fromVersion <= 89)) { 388acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen fromVersion = 63; 389702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Drop everything and start over. 390702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Log.i(TAG, "Upgrading media database from version " + 391702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project fromVersion + " to " + toVersion + ", which will destroy all old data"); 392702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS images"); 393702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS images_cleanup"); 394702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS thumbnails"); 395702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS thumbnails_cleanup"); 396702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS audio_meta"); 397702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS artists"); 398702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS albums"); 399702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS album_art"); 400702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP VIEW IF EXISTS artist_info"); 401702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP VIEW IF EXISTS album_info"); 402702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP VIEW IF EXISTS artists_albums_map"); 403702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS audio_meta_cleanup"); 404702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS audio_genres"); 405702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS audio_genres_map"); 406702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS audio_genres_cleanup"); 407702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS audio_playlists"); 408702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS audio_playlists_map"); 409702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS audio_playlists_cleanup"); 410702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS albumart_cleanup1"); 411702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS albumart_cleanup2"); 412702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TABLE IF EXISTS video"); 413702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS video_cleanup"); 4149ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood db.execSQL("DROP TRIGGER IF EXISTS images_objects_cleanup"); 4159ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood db.execSQL("DROP TRIGGER IF EXISTS audio_objects_cleanup"); 4169ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood db.execSQL("DROP TRIGGER IF EXISTS video_objects_cleanup"); 4179ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood db.execSQL("DROP TRIGGER IF EXISTS playlists_objects_cleanup"); 418702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 419702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS images (" + 420702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 421702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_data TEXT," + 422702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_size INTEGER," + 423702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_display_name TEXT," + 424702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "mime_type TEXT," + 425702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "title TEXT," + 426702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_added INTEGER," + 427702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_modified INTEGER," + 428702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "description TEXT," + 429702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "picasa_id TEXT," + 430702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "isprivate INTEGER," + 431702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "latitude DOUBLE," + 432702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "longitude DOUBLE," + 433702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "datetaken INTEGER," + 434702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "orientation INTEGER," + 435702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "mini_thumb_magic INTEGER," + 436702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "bucket_id TEXT," + 437702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "bucket_display_name TEXT" + 438702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 439702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 440702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE INDEX IF NOT EXISTS mini_thumb_magic_index on images(mini_thumb_magic);"); 441702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 442702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS images_cleanup DELETE ON images " + 443702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 444702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE FROM thumbnails WHERE image_id = old._id;" + 445702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT _DELETE_FILE(old._data);" + 446702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 447702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 448b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // create image thumbnail table 449702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS thumbnails (" + 450702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 451702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_data TEXT," + 452702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "image_id INTEGER," + 453702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "kind INTEGER," + 454702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "width INTEGER," + 455702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "height INTEGER" + 456702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 457702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 458702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE INDEX IF NOT EXISTS image_id_index on thumbnails(image_id);"); 459702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 460702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS thumbnails_cleanup DELETE ON thumbnails " + 461702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 462702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT _DELETE_FILE(old._data);" + 463702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 464702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 465702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains meta data about audio files 466702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS audio_meta (" + 467702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 468216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen "_data TEXT UNIQUE NOT NULL," + 469702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_display_name TEXT," + 470702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_size INTEGER," + 471702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "mime_type TEXT," + 472702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_added INTEGER," + 473702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_modified INTEGER," + 474702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "title TEXT NOT NULL," + 475702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "title_key TEXT NOT NULL," + 476702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "duration INTEGER," + 477702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "artist_id INTEGER," + 478702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "composer TEXT," + 479702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "album_id INTEGER," + 480702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "track INTEGER," + // track is an integer to allow proper sorting 481702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "year INTEGER CHECK(year!=0)," + 482702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "is_ringtone INTEGER," + 483702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "is_music INTEGER," + 484702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "is_alarm INTEGER," + 485702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "is_notification INTEGER" + 486702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 487702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 488702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains a sort/group "key" and the preferred display name for artists 489702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS artists (" + 490702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "artist_id INTEGER PRIMARY KEY," + 491702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "artist_key TEXT NOT NULL UNIQUE," + 492702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "artist TEXT NOT NULL" + 493702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 494702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 495702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains a sort/group "key" and the preferred display name for albums 496702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS albums (" + 497702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "album_id INTEGER PRIMARY KEY," + 498702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "album_key TEXT NOT NULL UNIQUE," + 499702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "album TEXT NOT NULL" + 500702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 501702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 502702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS album_art (" + 503702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "album_id INTEGER PRIMARY KEY," + 504702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_data TEXT" + 505702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 506702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 507702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project recreateAudioView(db); 50895ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen 509702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 510702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Provides some extra info about artists, like the number of tracks 511702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // and albums for this artist 512702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE VIEW IF NOT EXISTS artist_info AS " + 513702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT artist_id AS _id, artist, artist_key, " + 514acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen "COUNT(DISTINCT album) AS number_of_albums, " + 515702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "COUNT(*) AS number_of_tracks FROM audio WHERE is_music=1 "+ 516702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "GROUP BY artist_key;"); 517702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 518702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Provides extra info albums, such as the number of tracks 519702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE VIEW IF NOT EXISTS album_info AS " + 520702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT audio.album_id AS _id, album, album_key, " + 521702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "MIN(year) AS minyear, " + 522702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "MAX(year) AS maxyear, artist, artist_id, artist_key, " + 523702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "count(*) AS " + MediaStore.Audio.Albums.NUMBER_OF_SONGS + 524702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ",album_art._data AS album_art" + 525702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " FROM audio LEFT OUTER JOIN album_art ON audio.album_id=album_art.album_id" + 526702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " WHERE is_music=1 GROUP BY audio.album_id;"); 527702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 528acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // For a given artist_id, provides the album_id for albums on 529acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // which the artist appears. 530acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("CREATE VIEW IF NOT EXISTS artists_albums_map AS " + 531acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen "SELECT DISTINCT artist_id, album_id FROM audio_meta;"); 532acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen 533702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /* 534702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Only external media volumes can handle genres, playlists, etc. 535702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 536702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!internal) { 537702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Cleans up when an audio file is deleted 538702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS audio_meta_cleanup DELETE ON audio_meta " + 539702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 540702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE FROM audio_genres_map WHERE audio_id = old._id;" + 541702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE FROM audio_playlists_map WHERE audio_id = old._id;" + 542702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 543702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 544702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains audio genre definitions 545702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS audio_genres (" + 546702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 547702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "name TEXT NOT NULL" + 548702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 549702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 550702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contiains mappings between audio genres and audio files 551702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS audio_genres_map (" + 552702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 553702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_id INTEGER NOT NULL," + 554702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "genre_id INTEGER NOT NULL" + 555702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 556702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 557702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Cleans up when an audio genre is delete 558702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS audio_genres_cleanup DELETE ON audio_genres " + 559702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 560702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE FROM audio_genres_map WHERE genre_id = old._id;" + 561702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 562702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 563702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains audio playlist definitions 564702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS audio_playlists (" + 565702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 566702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_data TEXT," + // _data is path for file based playlists, or null 567702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "name TEXT NOT NULL," + 568702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_added INTEGER," + 569702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_modified INTEGER" + 570702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 571702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 572702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains mappings between audio playlists and audio files 573702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS audio_playlists_map (" + 574702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 575702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_id INTEGER NOT NULL," + 576702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "playlist_id INTEGER NOT NULL," + 577702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "play_order INTEGER NOT NULL" + 578702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 579702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 580702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Cleans up when an audio playlist is deleted 581702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS audio_playlists_cleanup DELETE ON audio_playlists " + 582702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 583702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE FROM audio_playlists_map WHERE playlist_id = old._id;" + 584702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT _DELETE_FILE(old._data);" + 585702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 586702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 587702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Cleans up album_art table entry when an album is deleted 588702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS albumart_cleanup1 DELETE ON albums " + 589702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 590702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE FROM album_art WHERE album_id = old.album_id;" + 591702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 592702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 593702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Cleans up album_art when an album is deleted 594702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS albumart_cleanup2 DELETE ON album_art " + 595702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 596702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT _DELETE_FILE(old._data);" + 597702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 598702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 599702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 600702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Contains meta data about video files 601702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TABLE IF NOT EXISTS video (" + 602702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_id INTEGER PRIMARY KEY," + 603702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_data TEXT NOT NULL," + 604702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_display_name TEXT," + 605702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "_size INTEGER," + 606702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "mime_type TEXT," + 607702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_added INTEGER," + 608702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "date_modified INTEGER," + 609702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "title TEXT," + 610702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "duration INTEGER," + 611702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "artist TEXT," + 612702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "album TEXT," + 613702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "resolution TEXT," + 614702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "description TEXT," + 615702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "isprivate INTEGER," + // for YouTube videos 616702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "tags TEXT," + // for YouTube videos 617702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "category TEXT," + // for YouTube videos 618702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "language TEXT," + // for YouTube videos 619702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "mini_thumb_data TEXT," + 620702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "latitude DOUBLE," + 621702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "longitude DOUBLE," + 622702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "datetaken INTEGER," + 623702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "mini_thumb_magic INTEGER" + 624702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 625702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 626702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS video_cleanup DELETE ON video " + 627702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 628702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT _DELETE_FILE(old._data);" + 629702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 630702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 631702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 632702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // At this point the database is at least at schema version 63 (it was 633702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // either created at version 63 by the code above, or was already at 634702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // version 63 or later) 635702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 636702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 64) { 637702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // create the index that updates the database to schema version 64 638702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE INDEX IF NOT EXISTS sort_index on images(datetaken ASC, _id ASC);"); 639702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 640702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 641acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen /* 642acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen * Android 1.0 shipped with database version 64 643acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen */ 644acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen 645702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 65) { 646702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // create the index that updates the database to schema version 65 647702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE INDEX IF NOT EXISTS titlekey_index on audio_meta(title_key);"); 648702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 649702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 650403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen // In version 66, originally we updateBucketNames(db, "images"), 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 if (fromVersion < 67) { 654702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // create the indices that update the database to schema version 67 655702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE INDEX IF NOT EXISTS albumkey_index on albums(album_key);"); 656702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE INDEX IF NOT EXISTS artistkey_index on artists(artist_key);"); 657702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 658702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 659702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 68) { 660702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Create bucket_id and bucket_display_name columns for the video table. 661702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("ALTER TABLE video ADD COLUMN bucket_id TEXT;"); 662702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("ALTER TABLE video ADD COLUMN bucket_display_name TEXT"); 663403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen 664403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen // In version 68, originally we updateBucketNames(db, "video"), 665403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen // but we need to do it in version 89 and therefore save the update here. 666702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 667702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 668702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 69) { 669702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project updateDisplayName(db, "images"); 670702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 671702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 672702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 70) { 673702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Create bookmark column for the video table. 674702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("ALTER TABLE video ADD COLUMN bookmark INTEGER;"); 675702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 67695ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen 677702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 71) { 678702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // There is no change to the database schema, however a code change 679702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // fixed parsing of metadata for certain files bought from the 680702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // iTunes music store, so we want to rescan files that might need it. 681702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // We do this by clearing the modification date in the database for 682702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // those files, so that the media scanner will see them as updated 683702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // and rescan them. 684702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("UPDATE audio_meta SET date_modified=0 WHERE _id IN (" + 685702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "SELECT _id FROM audio where mime_type='audio/mp4' AND " + 686e31cfb1a2c21e7ac7a646d40afbb48f49fab6907Marco Nelissen "artist='" + MediaStore.UNKNOWN_STRING + "' AND " + 687e31cfb1a2c21e7ac7a646d40afbb48f49fab6907Marco Nelissen "album='" + MediaStore.UNKNOWN_STRING + "'" + 688702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ");"); 689702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 69095ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen 691702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (fromVersion < 72) { 692702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Create is_podcast and bookmark columns for the audio table. 693702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("ALTER TABLE audio_meta ADD COLUMN is_podcast INTEGER;"); 694702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("UPDATE audio_meta SET is_podcast=1 WHERE _data LIKE '%/podcasts/%';"); 695702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("UPDATE audio_meta SET is_music=0 WHERE is_podcast=1" + 696702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " AND _data NOT LIKE '%/music/%';"); 697702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("ALTER TABLE audio_meta ADD COLUMN bookmark INTEGER;"); 698702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 699702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // New columns added to tables aren't visible in views on those tables 700702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // without opening and closing the database (or using the 'vacuum' command, 701702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // which we can't do here because all this code runs inside a transaction). 702702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // To work around this, we drop and recreate the affected view and trigger. 703702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project recreateAudioView(db); 704702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 70595ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen 706acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen /* 707acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen * Android 1.5 shipped with database version 72 708acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen */ 709acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen 7108d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen if (fromVersion < 73) { 7118d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen // There is no change to the database schema, but we now do case insensitive 7128d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen // matching of folder names when determining whether something is music, a 7138d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen // ringtone, podcast, etc, so we might need to reclassify some files. 7148d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen db.execSQL("UPDATE audio_meta SET is_music=1 WHERE is_music=0 AND " + 7158d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen "_data LIKE '%/music/%';"); 7168d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen db.execSQL("UPDATE audio_meta SET is_ringtone=1 WHERE is_ringtone=0 AND " + 7178d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen "_data LIKE '%/ringtones/%';"); 7188d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen db.execSQL("UPDATE audio_meta SET is_notification=1 WHERE is_notification=0 AND " + 7198d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen "_data LIKE '%/notifications/%';"); 7208d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen db.execSQL("UPDATE audio_meta SET is_alarm=1 WHERE is_alarm=0 AND " + 7218d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen "_data LIKE '%/alarms/%';"); 7228d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen db.execSQL("UPDATE audio_meta SET is_podcast=1 WHERE is_podcast=0 AND " + 7238d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen "_data LIKE '%/podcasts/%';"); 7248d85ef81ed5f1604d40eb8a321fafd2079ada030Marco Nelissen } 725a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen 726a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen if (fromVersion < 74) { 727a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // This view is used instead of the audio view by the union below, to force 728a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // sqlite to use the title_key index. This greatly reduces memory usage 729a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // (no separate copy pass needed for sorting, which could cause errors on 730a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // large datasets) and improves speed (by about 35% on a large dataset) 731a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen db.execSQL("CREATE VIEW IF NOT EXISTS searchhelpertitle AS SELECT * FROM audio " + 732a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "ORDER BY title_key;"); 733a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen 734a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen db.execSQL("CREATE VIEW IF NOT EXISTS search AS " + 735a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "SELECT _id," + 736a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "'artist' AS mime_type," + 737a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist," + 738a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS album," + 739a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS title," + 740a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist AS text1," + 741a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS text2," + 742a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "number_of_albums AS data1," + 743a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "number_of_tracks AS data2," + 744a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist_key AS match," + 745a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "'content://media/external/audio/artists/'||_id AS suggest_intent_data," + 746a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "1 AS grouporder " + 747e31cfb1a2c21e7ac7a646d40afbb48f49fab6907Marco Nelissen "FROM artist_info WHERE (artist!='" + MediaStore.UNKNOWN_STRING + "') " + 748a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "UNION ALL " + 749a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "SELECT _id," + 750a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "'album' AS mime_type," + 751a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist," + 752a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "album," + 753a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS title," + 754a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "album AS text1," + 755a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist AS text2," + 756a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS data1," + 757a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS data2," + 758a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist_key||' '||album_key AS match," + 759a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "'content://media/external/audio/albums/'||_id AS suggest_intent_data," + 760a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "2 AS grouporder " + 761e31cfb1a2c21e7ac7a646d40afbb48f49fab6907Marco Nelissen "FROM album_info WHERE (album!='" + MediaStore.UNKNOWN_STRING + "') " + 762a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "UNION ALL " + 763a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "SELECT searchhelpertitle._id AS _id," + 764a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "mime_type," + 765a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist," + 766a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "album," + 767a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "title," + 768a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "title AS text1," + 769a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist AS text2," + 770a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS data1," + 771a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "NULL AS data2," + 772a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "artist_key||' '||album_key||' '||title_key AS match," + 773a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "'content://media/external/audio/media/'||searchhelpertitle._id AS " + 774a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "suggest_intent_data," + 775a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "3 AS grouporder " + 776a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "FROM searchhelpertitle WHERE (title != '') " 777a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen ); 778a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen } 77959948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen 78059948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen if (fromVersion < 75) { 78195ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen // Force a rescan of the audio entries so we can apply the new logic to 78259948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // distinguish same-named albums. 78359948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen db.execSQL("UPDATE audio_meta SET date_modified=0;"); 78459948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen db.execSQL("DELETE FROM albums"); 78559948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen } 78615d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen 78715d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen if (fromVersion < 76) { 78815d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen // We now ignore double quotes when building the key, so we have to remove all of them 78915d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen // from existing keys. 79015d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen db.execSQL("UPDATE audio_meta SET title_key=" + 79115d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen "REPLACE(title_key,x'081D08C29F081D',x'081D') " + 79215d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen "WHERE title_key LIKE '%'||x'081D08C29F081D'||'%';"); 79315d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen db.execSQL("UPDATE albums SET album_key=" + 79415d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen "REPLACE(album_key,x'081D08C29F081D',x'081D') " + 79515d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen "WHERE album_key LIKE '%'||x'081D08C29F081D'||'%';"); 79615d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen db.execSQL("UPDATE artists SET artist_key=" + 79715d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen "REPLACE(artist_key,x'081D08C29F081D',x'081D') " + 79815d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen "WHERE artist_key LIKE '%'||x'081D08C29F081D'||'%';"); 79915d7507838ad66cfebc7d730d143d27ea04736f8Marco Nelissen } 800b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 801acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen /* 802acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen * Android 1.6 shipped with database version 76 803acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen */ 804acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen 805b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (fromVersion < 77) { 806b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // create video thumbnail table 807b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen db.execSQL("CREATE TABLE IF NOT EXISTS videothumbnails (" + 808b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "_id INTEGER PRIMARY KEY," + 809b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "_data TEXT," + 810b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "video_id INTEGER," + 811b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "kind INTEGER," + 812b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "width INTEGER," + 813b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "height INTEGER" + 814b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen ");"); 815b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 816b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen db.execSQL("CREATE INDEX IF NOT EXISTS video_id_index on videothumbnails(video_id);"); 817b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 818b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen db.execSQL("CREATE TRIGGER IF NOT EXISTS videothumbnails_cleanup DELETE ON videothumbnails " + 819b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "BEGIN " + 820b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "SELECT _DELETE_FILE(old._data);" + 821b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "END"); 822b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 8231769168ade7b67f8695a4e4f3c69625aca0811d5Ray Chen 824acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen /* 825acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen * Android 2.0 and 2.0.1 shipped with database version 77 826acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen */ 827acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen 8281769168ade7b67f8695a4e4f3c69625aca0811d5Ray Chen if (fromVersion < 78) { 829044b029d9023f55e8e8861ed2f6e192f1b34f9bbRay Chen // Force a rescan of the video entries so we can update 8301769168ade7b67f8695a4e4f3c69625aca0811d5Ray Chen // latest changed DATE_TAKEN units (in milliseconds). 8311769168ade7b67f8695a4e4f3c69625aca0811d5Ray Chen db.execSQL("UPDATE video SET date_modified=0;"); 8321769168ade7b67f8695a4e4f3c69625aca0811d5Ray Chen } 833268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen 834acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen /* 835acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen * Android 2.1 shipped with database version 78 836acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen */ 837acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen 838268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen if (fromVersion < 79) { 839268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen // move /sdcard/albumthumbs to 840268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen // /sdcard/Android/data/com.android.providers.media/albumthumbs, 841268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen // and update the database accordingly 842268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen 843268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen String storageroot = Environment.getExternalStorageDirectory().getAbsolutePath(); 844268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen String oldthumbspath = storageroot + "/albumthumbs"; 845268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen String newthumbspath = storageroot + "/" + ALBUM_THUMB_FOLDER; 846268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen File thumbsfolder = new File(oldthumbspath); 847268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen if (thumbsfolder.exists()) { 848268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen // move folder to its new location 849268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen File newthumbsfolder = new File(newthumbspath); 850268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen newthumbsfolder.getParentFile().mkdirs(); 851268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen if(thumbsfolder.renameTo(newthumbsfolder)) { 852268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen // update the database 853268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen db.execSQL("UPDATE album_art SET _data=REPLACE(_data, '" + 854268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen oldthumbspath + "','" + newthumbspath + "');"); 855268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen } 856268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen } 857268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen } 858044b029d9023f55e8e8861ed2f6e192f1b34f9bbRay Chen 859044b029d9023f55e8e8861ed2f6e192f1b34f9bbRay Chen if (fromVersion < 80) { 860044b029d9023f55e8e8861ed2f6e192f1b34f9bbRay Chen // Force rescan of image entries to update DATE_TAKEN as UTC timestamp. 861044b029d9023f55e8e8861ed2f6e192f1b34f9bbRay Chen db.execSQL("UPDATE images SET date_modified=0;"); 862044b029d9023f55e8e8861ed2f6e192f1b34f9bbRay Chen } 8630ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen 864166a4e3cc66a645cc5e11d2f06d059512def0aceMarco Nelissen if (fromVersion < 81 && !internal) { 8650ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // Delete entries starting with /mnt/sdcard. This is for the benefit 8660ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // of users running builds between 2.0.1 and 2.1 final only, since 8670ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // users updating from 2.0 or earlier will not have such entries. 8680ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen 8690ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // First we need to update the _data fields in the affected tables, since 8700ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // otherwise deleting the entries will also delete the underlying files 8710ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // (via a trigger), and we want to keep them. 8720ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE audio_playlists SET _data='////' WHERE _data LIKE '/mnt/sdcard/%';"); 8730ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE images SET _data='////' WHERE _data LIKE '/mnt/sdcard/%';"); 8740ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE video SET _data='////' WHERE _data LIKE '/mnt/sdcard/%';"); 8750ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE videothumbnails SET _data='////' WHERE _data LIKE '/mnt/sdcard/%';"); 8760ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE thumbnails SET _data='////' WHERE _data LIKE '/mnt/sdcard/%';"); 8770ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE album_art SET _data='////' WHERE _data LIKE '/mnt/sdcard/%';"); 878216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen db.execSQL("UPDATE audio_meta SET _data='////' WHERE _data LIKE '/mnt/sdcard/%';"); 8790ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // Once the paths have been renamed, we can safely delete the entries 8800ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE FROM audio_playlists WHERE _data IS '////';"); 8810ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE FROM images WHERE _data IS '////';"); 8820ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE FROM video WHERE _data IS '////';"); 8830ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE FROM videothumbnails WHERE _data IS '////';"); 8840ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE FROM thumbnails WHERE _data IS '////';"); 8850ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE FROM audio_meta WHERE _data IS '////';"); 8860ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE FROM album_art WHERE _data IS '////';"); 8870ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen 8880ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // rename existing entries starting with /sdcard to /mnt/sdcard 8890ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE audio_meta" + 8900ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen " SET _data='/mnt/sdcard'||SUBSTR(_data,8) WHERE _data LIKE '/sdcard/%';"); 8910ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE audio_playlists" + 8920ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen " SET _data='/mnt/sdcard'||SUBSTR(_data,8) WHERE _data LIKE '/sdcard/%';"); 8930ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE images" + 8940ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen " SET _data='/mnt/sdcard'||SUBSTR(_data,8) WHERE _data LIKE '/sdcard/%';"); 8950ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE video" + 8960ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen " SET _data='/mnt/sdcard'||SUBSTR(_data,8) WHERE _data LIKE '/sdcard/%';"); 8970ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE videothumbnails" + 8980ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen " SET _data='/mnt/sdcard'||SUBSTR(_data,8) WHERE _data LIKE '/sdcard/%';"); 8990ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE thumbnails" + 9000ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen " SET _data='/mnt/sdcard'||SUBSTR(_data,8) WHERE _data LIKE '/sdcard/%';"); 9010ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE album_art" + 9020ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen " SET _data='/mnt/sdcard'||SUBSTR(_data,8) WHERE _data LIKE '/sdcard/%';"); 9030ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen 9040ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // Delete albums and artists, then clear the modification time on songs, which 9050ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // will cause the media scanner to rescan everything, rebuilding the artist and 9060ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // album tables along the way, while preserving playlists. 9070ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // We need this rescan because ICU also changed, and now generates different 9080ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen // collation keys 9090ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE from albums"); 9100ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("DELETE from artists"); 9110ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen db.execSQL("UPDATE audio_meta SET date_modified=0;"); 9120ba6af212288010ca16b08f8be3985edb287cb0fMarco Nelissen } 91384403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen 91484403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen if (fromVersion < 82) { 915acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // recreate this view with the correct "group by" specifier 91684403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen db.execSQL("DROP VIEW IF EXISTS artist_info"); 91784403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen db.execSQL("CREATE VIEW IF NOT EXISTS artist_info AS " + 91884403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen "SELECT artist_id AS _id, artist, artist_key, " + 919acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen "COUNT(DISTINCT album_key) AS number_of_albums, " + 92084403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen "COUNT(*) AS number_of_tracks FROM audio WHERE is_music=1 "+ 92184403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen "GROUP BY artist_key;"); 92284403f9475c71ba53fa9bedfc9953d9f0ad0fc2cMarco Nelissen } 923216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen 924acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen /* we skipped over version 83, and reverted versions 84, 85 and 86 */ 925ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen 926ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen if (fromVersion < 87) { 927ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen // The fastscroll thumb needs an index on the strings being displayed, 928ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen // otherwise the queries it does to determine the correct position 929ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen // becomes really inefficient 930022eb71bfe8ec65b8817eaa432a530194210ec23Marco Nelissen db.execSQL("CREATE INDEX IF NOT EXISTS title_idx on audio_meta(title);"); 931022eb71bfe8ec65b8817eaa432a530194210ec23Marco Nelissen db.execSQL("CREATE INDEX IF NOT EXISTS artist_idx on artists(artist);"); 932022eb71bfe8ec65b8817eaa432a530194210ec23Marco Nelissen db.execSQL("CREATE INDEX IF NOT EXISTS album_idx on albums(album);"); 933ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen } 934216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen 935acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen if (fromVersion < 88) { 936acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // Clean up a few more things from versions 84/85/86, and recreate 937acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // the few things worth keeping from those changes. 938acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS albums_update1;"); 939acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS albums_update2;"); 940acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS albums_update3;"); 941acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS albums_update4;"); 942acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS artist_update1;"); 943acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS artist_update2;"); 944acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS artist_update3;"); 945acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP TRIGGER IF EXISTS artist_update4;"); 946acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("DROP VIEw IF EXISTS album_artists;"); 947acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("CREATE INDEX IF NOT EXISTS album_id_idx on audio_meta(album_id);"); 948acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("CREATE INDEX IF NOT EXISTS artist_id_idx on audio_meta(artist_id);"); 949acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // For a given artist_id, provides the album_id for albums on 950acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // which the artist appears. 951acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen db.execSQL("CREATE VIEW IF NOT EXISTS artists_albums_map AS " + 952acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen "SELECT DISTINCT artist_id, album_id FROM audio_meta;"); 953acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen } 954403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen 955403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen if (fromVersion < 89) { 956403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen updateBucketNames(db, "images"); 957403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen updateBucketNames(db, "video"); 958403ebe07562bb44334724fde9749c22479204662Wei-Ta Chen } 959b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 960b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood if (fromVersion < 91) { 961b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood // A table containing information for all files, 962b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood // needed for MTP support 963b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood db.execSQL("CREATE TABLE IF NOT EXISTS objects (" + 964b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood "_id INTEGER PRIMARY KEY," + 965b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood "_data TEXT NOT NULL," + 966b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood "_size INTEGER," + 967b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood "format INTEGER," + 968b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood "parent INTEGER," + 969b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood "date_modified INTEGER" + 970b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood ");"); 971b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } 9721717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood if (fromVersion < 92) { 9731717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood // Add columns for cross referencing to media tables 9741717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood // media_table is the name of the table for the object, 9751717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood // and media_id is the ID of the object in that table 9761717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood db.execSQL("ALTER TABLE objects ADD COLUMN media_table INTEGER;"); 9771717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood db.execSQL("ALTER TABLE objects ADD COLUMN media_id INTEGER;"); 9781717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood } 9799ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood if (fromVersion < 93) { 9809ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood // cleans up objects table when an image file is deleted 9819ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood db.execSQL("CREATE TRIGGER IF NOT EXISTS images_objects_cleanup DELETE ON images " + 9829ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood "BEGIN " + 9839ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood "DELETE FROM objects WHERE media_table = 1 AND media_id = old._id;" + 9849ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood "END"); 9859ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood 9869ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood 9879ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood // cleans up objects table when an audio file is deleted 9889ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood db.execSQL("CREATE TRIGGER IF NOT EXISTS audio_objects_cleanup DELETE ON audio_meta " + 9899ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood "BEGIN " + 9909ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood "DELETE FROM objects WHERE media_table = 100 AND media_id = old._id;" + 9919ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood "END"); 9929ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood 9939ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood 9949ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood // cleans up objects table when a video file is deleted 9959ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood db.execSQL("CREATE TRIGGER IF NOT EXISTS video_objects_cleanup DELETE ON video " + 9969ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood "BEGIN " + 9979ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood "DELETE FROM objects WHERE media_table = 200 AND media_id = old._id;" + 9989ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood "END"); 9999ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood 10009ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood 10019ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood // cleans up objects table when a playlist file is deleted 10029ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood db.execSQL("CREATE TRIGGER IF NOT EXISTS playlists_objects_cleanup DELETE ON audio_playlists " + 10039ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood "BEGIN " + 10049ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood "DELETE FROM objects WHERE media_table = 110 AND media_id = old._id;" + 10059ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood "END"); 10069ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood } 1007acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen sanityCheck(db, fromVersion); 10081d4a8ec9e1e62427088dc40f08872a10c863535eMarco Nelissen } 10091d4a8ec9e1e62427088dc40f08872a10c863535eMarco Nelissen 10101d4a8ec9e1e62427088dc40f08872a10c863535eMarco Nelissen /** 1011216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen * Perform a simple sanity check on the database. Currently this tests 1012216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen * whether all the _data entries in audio_meta are unique 1013216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen */ 1014216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen private static void sanityCheck(SQLiteDatabase db, int fromVersion) { 1015216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen Cursor c1 = db.query("audio_meta", new String[] {"count(*)"}, 1016216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen null, null, null, null, null); 1017216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen Cursor c2 = db.query("audio_meta", new String[] {"count(distinct _data)"}, 1018216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen null, null, null, null, null); 1019216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen c1.moveToFirst(); 1020216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen c2.moveToFirst(); 1021216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen int num1 = c1.getInt(0); 1022216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen int num2 = c2.getInt(0); 1023216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen c1.close(); 1024216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen c2.close(); 1025216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen if (num1 != num2) { 1026216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen Log.e(TAG, "audio_meta._data column is not unique while upgrading" + 1027216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen " from schema " +fromVersion + " : " + num1 +"/" + num2); 1028216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen // Delete all audio_meta rows so they will be rebuilt by the media scanner 1029216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen db.execSQL("DELETE FROM audio_meta;"); 1030216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen } 1031702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1032702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1033702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static void recreateAudioView(SQLiteDatabase db) { 1034702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Provides a unified audio/artist/album info view. 1035702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Note that views are read-only, so we define a trigger to allow deletes. 1036702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP VIEW IF EXISTS audio"); 1037702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("DROP TRIGGER IF EXISTS audio_delete"); 1038702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE VIEW IF NOT EXISTS audio as SELECT * FROM audio_meta " + 1039702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "LEFT OUTER JOIN artists ON audio_meta.artist_id=artists.artist_id " + 1040702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "LEFT OUTER JOIN albums ON audio_meta.album_id=albums.album_id;"); 1041702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1042702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.execSQL("CREATE TRIGGER IF NOT EXISTS audio_delete INSTEAD OF DELETE ON audio " + 1043702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "BEGIN " + 1044702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE from audio_meta where _id=old._id;" + 1045702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE from audio_playlists_map where audio_id=old._id;" + 1046702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "DELETE from audio_genres_map where audio_id=old._id;" + 1047702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "END"); 1048702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 104995ff0f28fc2c15fea233e3d2ce71eeea3f1a4942Ray Chen 1050702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 1051702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Iterate through the rows of a table in a database, ensuring that the bucket_id and 1052702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * bucket_display_name columns are correct. 1053702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param db 1054702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param tableName 1055702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 1056702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static void updateBucketNames(SQLiteDatabase db, String tableName) { 1057702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Rebuild the bucket_display_name column using the natural case rather than lower case. 1058702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.beginTransaction(); 1059702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 1060702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String[] columns = {BaseColumns._ID, MediaColumns.DATA}; 1061702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Cursor cursor = db.query(tableName, columns, null, null, null, null, null); 1062702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 1063702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final int idColumnIndex = cursor.getColumnIndex(BaseColumns._ID); 1064702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final int dataColumnIndex = cursor.getColumnIndex(MediaColumns.DATA); 1065702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project while (cursor.moveToNext()) { 1066702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String data = cursor.getString(dataColumnIndex); 1067702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(); 1068702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project computeBucketValues(data, values); 1069702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int rowId = cursor.getInt(idColumnIndex); 1070702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.update(tableName, values, "_id=" + rowId, null); 1071702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1072702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 1073702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project cursor.close(); 1074702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1075702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.setTransactionSuccessful(); 1076702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 1077702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.endTransaction(); 1078702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1079702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1080702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1081702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 1082702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Iterate through the rows of a table in a database, ensuring that the 1083702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * display name column has a value. 1084702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param db 1085702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param tableName 1086702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 1087702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static void updateDisplayName(SQLiteDatabase db, String tableName) { 1088702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Fill in default values for null displayName values 1089702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.beginTransaction(); 1090702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 1091702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String[] columns = {BaseColumns._ID, MediaColumns.DATA, MediaColumns.DISPLAY_NAME}; 1092702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Cursor cursor = db.query(tableName, columns, null, null, null, null, null); 1093702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 1094702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final int idColumnIndex = cursor.getColumnIndex(BaseColumns._ID); 1095702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final int dataColumnIndex = cursor.getColumnIndex(MediaColumns.DATA); 1096702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project final int displayNameIndex = cursor.getColumnIndex(MediaColumns.DISPLAY_NAME); 1097702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(); 1098702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project while (cursor.moveToNext()) { 1099702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String displayName = cursor.getString(displayNameIndex); 1100702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (displayName == null) { 1101702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String data = cursor.getString(dataColumnIndex); 1102702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.clear(); 1103702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project computeDisplayName(data, values); 1104702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int rowId = cursor.getInt(idColumnIndex); 1105702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.update(tableName, values, "_id=" + rowId, null); 1106702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1107702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1108702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 1109702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project cursor.close(); 1110702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1111702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.setTransactionSuccessful(); 1112702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 1113702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.endTransaction(); 1114702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1115702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1116702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 1117702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param data The input path 1118702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param values the content values, where the bucked id name and bucket display name are updated. 1119702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 1120702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 1121702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1122702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static void computeBucketValues(String data, ContentValues values) { 1123702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File parentFile = new File(data).getParentFile(); 1124702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (parentFile == null) { 1125702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project parentFile = new File("/"); 1126702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1127702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1128702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Lowercase the path for hashing. This avoids duplicate buckets if the 1129702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // filepath case is changed externally. 1130702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Keep the original case for display. 1131702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String path = parentFile.toString().toLowerCase(); 1132702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String name = parentFile.getName(); 1133702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1134702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Note: the BUCKET_ID and BUCKET_DISPLAY_NAME attributes are spelled the 1135702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // same for both images and video. However, for backwards-compatibility reasons 1136702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // there is no common base class. We use the ImageColumns version here 1137702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(ImageColumns.BUCKET_ID, path.hashCode()); 1138702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(ImageColumns.BUCKET_DISPLAY_NAME, name); 1139702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1140702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1141702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 1142702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param data The input path 1143702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param values the content values, where the display name is updated. 1144702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 1145702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 1146702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static void computeDisplayName(String data, ContentValues values) { 1147702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String s = (data == null ? "" : data.toString()); 1148702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int idx = s.lastIndexOf('/'); 1149702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (idx >= 0) { 1150702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project s = s.substring(idx + 1); 1151702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1152702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put("_display_name", s); 1153702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1154702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1155b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen /** 1156498b62c2912302a23532c73a028a7684c5df33caRay Chen * Copy taken time from date_modified if we lost the original value (e.g. after factory reset) 1157498b62c2912302a23532c73a028a7684c5df33caRay Chen * This works for both video and image tables. 1158b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen * 1159b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen * @param values the content values, where taken time is updated. 1160b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen */ 1161b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen private static void computeTakenTime(ContentValues values) { 1162b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen if (! values.containsKey(Images.Media.DATE_TAKEN)) { 1163b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen // This only happens when MediaScanner finds an image file that doesn't have any useful 1164b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen // reference to get this value. (e.g. GPSTimeStamp) 1165498b62c2912302a23532c73a028a7684c5df33caRay Chen Long lastModified = values.getAsLong(MediaColumns.DATE_MODIFIED); 1166b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen if (lastModified != null) { 1167b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen values.put(Images.Media.DATE_TAKEN, lastModified * 1000); 1168b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen } 1169b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen } 1170b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen } 1171b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen 1172b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen /** 1173b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen * This method blocks until thumbnail is ready. 1174b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen * 1175b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen * @param thumbUri 1176b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen * @return 1177b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen */ 1178b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private boolean waitForThumbnailReady(Uri origUri) { 1179b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen Cursor c = this.query(origUri, new String[] { ImageColumns._ID, ImageColumns.DATA, 1180b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen ImageColumns.MINI_THUMB_MAGIC}, null, null, null); 1181b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (c == null) return false; 1182b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1183b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen boolean result = false; 1184b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1185b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (c.moveToFirst()) { 1186e263c2a4b880ef8a5314bb4379c74bf5f9292bd0Ray Chen long id = c.getLong(0); 1187b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen String path = c.getString(1); 1188b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen long magic = c.getLong(2); 1189b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 11909299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen MediaThumbRequest req = requestMediaThumbnail(path, origUri, 11919299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen MediaThumbRequest.PRIORITY_HIGH, magic); 11929299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen if (req == null) { 11939299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen return false; 11949299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen } 11959299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen synchronized (req) { 11969299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen try { 11979299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen while (req.mState == MediaThumbRequest.State.WAIT) { 11989299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen req.wait(); 119920434e032e498b716f87cce2f23dd646819218bfRay Chen } 12009299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen } catch (InterruptedException e) { 12019299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen Log.w(TAG, e); 12029299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen } 12039299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen if (req.mState == MediaThumbRequest.State.DONE) { 12049299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen result = true; 1205b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1206b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1207b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1208b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen c.close(); 1209b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1210b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return result; 1211b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1212b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1213e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen private boolean matchThumbRequest(MediaThumbRequest req, int pid, long id, long gid, 1214e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen boolean isVideo) { 1215e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen boolean cancelAllOrigId = (id == -1); 1216e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen boolean cancelAllGroupId = (gid == -1); 1217e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen return (req.mCallingPid == pid) && 1218e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen (cancelAllGroupId || req.mGroupId == gid) && 1219e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen (cancelAllOrigId || req.mOrigId == id) && 1220e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen (req.mIsVideo == isVideo); 1221e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen } 1222e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen 1223b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private boolean queryThumbnail(SQLiteQueryBuilder qb, Uri uri, String table, 1224b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen String column, boolean hasThumbnailId) { 1225b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen qb.setTables(table); 1226b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (hasThumbnailId) { 1227b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // For uri dispatched to this method, the 4th path segment is always 1228b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // the thumbnail id. 1229b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen qb.appendWhere("_id = " + uri.getPathSegments().get(3)); 1230b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // client already knows which thumbnail it wants, bypass it. 1231b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return true; 1232b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1233b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen String origId = uri.getQueryParameter("orig_id"); 1234b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // We can't query ready_flag unless we know original id 1235b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (origId == null) { 1236b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // this could be thumbnail query for other purpose, bypass it. 1237b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return true; 1238b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1239b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1240b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen boolean needBlocking = "1".equals(uri.getQueryParameter("blocking")); 124120434e032e498b716f87cce2f23dd646819218bfRay Chen boolean cancelRequest = "1".equals(uri.getQueryParameter("cancel")); 1242e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen Uri origUri = uri.buildUpon().encodedPath( 1243e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen uri.getPath().replaceFirst("thumbnails", "media")) 1244e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen .appendPath(origId).build(); 1245b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1246b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (needBlocking && !waitForThumbnailReady(origUri)) { 124720434e032e498b716f87cce2f23dd646819218bfRay Chen Log.w(TAG, "original media doesn't exist or it's canceled."); 1248b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return false; 124920434e032e498b716f87cce2f23dd646819218bfRay Chen } else if (cancelRequest) { 1250e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen String groupId = uri.getQueryParameter("group_id"); 1251e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen boolean isVideo = "video".equals(uri.getPathSegments().get(1)); 125220434e032e498b716f87cce2f23dd646819218bfRay Chen int pid = Binder.getCallingPid(); 125320434e032e498b716f87cce2f23dd646819218bfRay Chen long id = -1; 1254e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen long gid = -1; 1255e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen 125620434e032e498b716f87cce2f23dd646819218bfRay Chen try { 125720434e032e498b716f87cce2f23dd646819218bfRay Chen id = Long.parseLong(origId); 1258e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen gid = Long.parseLong(groupId); 125920434e032e498b716f87cce2f23dd646819218bfRay Chen } catch (NumberFormatException ex) { 126020434e032e498b716f87cce2f23dd646819218bfRay Chen // invalid cancel request 126120434e032e498b716f87cce2f23dd646819218bfRay Chen return false; 126220434e032e498b716f87cce2f23dd646819218bfRay Chen } 1263e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen 126420434e032e498b716f87cce2f23dd646819218bfRay Chen synchronized (mMediaThumbQueue) { 1265e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen if (mCurrentThumbRequest != null && 1266e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen matchThumbRequest(mCurrentThumbRequest, pid, id, gid, isVideo)) { 126720434e032e498b716f87cce2f23dd646819218bfRay Chen synchronized (mCurrentThumbRequest) { 126820434e032e498b716f87cce2f23dd646819218bfRay Chen mCurrentThumbRequest.mState = MediaThumbRequest.State.CANCEL; 126920434e032e498b716f87cce2f23dd646819218bfRay Chen mCurrentThumbRequest.notifyAll(); 127020434e032e498b716f87cce2f23dd646819218bfRay Chen } 127120434e032e498b716f87cce2f23dd646819218bfRay Chen } 127220434e032e498b716f87cce2f23dd646819218bfRay Chen for (MediaThumbRequest mtq : mMediaThumbQueue) { 1273e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen if (matchThumbRequest(mtq, pid, id, gid, isVideo)) { 127420434e032e498b716f87cce2f23dd646819218bfRay Chen synchronized (mtq) { 127520434e032e498b716f87cce2f23dd646819218bfRay Chen mtq.mState = MediaThumbRequest.State.CANCEL; 127620434e032e498b716f87cce2f23dd646819218bfRay Chen mtq.notifyAll(); 127720434e032e498b716f87cce2f23dd646819218bfRay Chen } 127820434e032e498b716f87cce2f23dd646819218bfRay Chen 127920434e032e498b716f87cce2f23dd646819218bfRay Chen mMediaThumbQueue.remove(mtq); 128020434e032e498b716f87cce2f23dd646819218bfRay Chen } 128120434e032e498b716f87cce2f23dd646819218bfRay Chen } 128220434e032e498b716f87cce2f23dd646819218bfRay Chen } 1283b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1284b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1285b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (origId != null) { 1286b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen qb.appendWhere(column + " = " + origId); 1287b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1288b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return true; 1289b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1290b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen @SuppressWarnings("fallthrough") 1291702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 1292702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public Cursor query(Uri uri, String[] projectionIn, String selection, 1293702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String[] selectionArgs, String sort) { 1294702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int table = URI_MATCHER.match(uri); 1295702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 129601a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen // Log.v(TAG, "query: uri="+uri+", selection="+selection); 1297702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // handle MEDIA_SCANNER before calling getDatabaseForUri() 1298702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (table == MEDIA_SCANNER) { 1299702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (mMediaScannerVolume == null) { 1300702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return null; 1301702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 1302702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // create a cursor to return volume currently being scanned by the media scanner 13030027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen MatrixCursor c = new MatrixCursor(new String[] {MediaStore.MEDIA_SCANNER_VOLUME}); 13040027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen c.addRow(new String[] {mMediaScannerVolume}); 13050027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen return c; 1306702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1307702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1308702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 13090027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen // Used temporarily (until we have unique media IDs) to get an identifier 13100027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen // for the current sd card, so that the music app doesn't have to use the 13110027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen // non-public getFatVolumeId method 13120027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen if (table == FS_ID) { 13130027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen MatrixCursor c = new MatrixCursor(new String[] {"fsid"}); 13140027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen c.addRow(new Integer[] {mVolumeId}); 13150027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen return c; 13160027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen } 13170027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen 1318702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String groupBy = null; 1319702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DatabaseHelper database = getDatabaseForUri(uri); 1320702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (database == null) { 1321702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return null; 1322702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1323702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteDatabase db = database.getReadableDatabase(); 1324702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 13254574e03055af60fada50481f2b34e19a687d5866Marco Nelissen String limit = uri.getQueryParameter("limit"); 1326b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen boolean hasThumbnailId = false; 1327702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1328702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (table) { 1329702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA: 1330702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("images"); 1331702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (uri.getQueryParameter("distinct") != null) 1332702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setDistinct(true); 1333702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1334702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // set the project map so that data dir is prepended to _data. 1335702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project //qb.setProjectionMap(mImagesProjectionMap, true); 1336702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1337702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1338702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA_ID: 1339702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("images"); 1340702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (uri.getQueryParameter("distinct") != null) 1341702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setDistinct(true); 1342702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1343702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // set the project map so that data dir is prepended to _data. 1344702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project //qb.setProjectionMap(mImagesProjectionMap, true); 1345702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id = " + uri.getPathSegments().get(3)); 1346702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1347702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1348702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_THUMBNAILS_ID: 1349b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen hasThumbnailId = true; 1350b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case IMAGES_THUMBNAILS: 1351b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (!queryThumbnail(qb, uri, "thumbnails", "image_id", hasThumbnailId)) { 1352b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return null; 1353b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1354702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1355702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1356702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA: 1357d9672f4d28ab9038333a0037fe30e386ac0ce610Marco Nelissen if (projectionIn != null && projectionIn.length == 1 && selectionArgs == null 1358ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen && (selection == null || selection.equalsIgnoreCase("is_music=1") 1359ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen || selection.equalsIgnoreCase("is_podcast=1") ) 1360ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen && projectionIn[0].equalsIgnoreCase("count(*)") ) { 1361ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen //Log.i("@@@@", "taking fast path for counting songs"); 1362ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.setTables("audio_meta"); 1363ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen } else { 1364ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.setTables("audio"); 1365ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen } 1366702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1367702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1368702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID: 1369702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio"); 1370702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id=" + uri.getPathSegments().get(3)); 1371702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1372702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1373702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES: 1374702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_genres"); 1375702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id IN (SELECT genre_id FROM " + 1376702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_genres_map WHERE audio_id = " + 1377702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project uri.getPathSegments().get(3) + ")"); 1378702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1379702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1380702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES_ID: 1381702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_genres"); 1382702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id=" + uri.getPathSegments().get(5)); 1383702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1384702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1385702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS: 1386702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_playlists"); 1387702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id IN (SELECT playlist_id FROM " + 1388702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_playlists_map WHERE audio_id = " + 1389702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project uri.getPathSegments().get(3) + ")"); 1390702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1391702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1392702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS_ID: 1393702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_playlists"); 1394702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id=" + uri.getPathSegments().get(5)); 1395702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1396702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1397702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES: 1398702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_genres"); 1399702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1400702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1401702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID: 1402702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_genres"); 1403702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id=" + uri.getPathSegments().get(3)); 1404702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1405702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1406702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID_MEMBERS: 1407702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio"); 1408702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id IN (SELECT audio_id FROM " + 1409702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_genres_map WHERE genre_id = " + 1410702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project uri.getPathSegments().get(3) + ")"); 1411702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1412702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1413702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID_MEMBERS_ID: 1414702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio"); 1415702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id=" + uri.getPathSegments().get(5)); 1416702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1417702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1418702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS: 1419702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_playlists"); 1420702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1421702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1422702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID: 1423702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_playlists"); 1424702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id=" + uri.getPathSegments().get(3)); 1425702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1426702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1427702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS: 142897e61d89d90a1bd6989a254660aa80553662e002Marco Nelissen if (projectionIn != null) { 142997e61d89d90a1bd6989a254660aa80553662e002Marco Nelissen for (int i = 0; i < projectionIn.length; i++) { 143097e61d89d90a1bd6989a254660aa80553662e002Marco Nelissen if (projectionIn[i].equals("_id")) { 143197e61d89d90a1bd6989a254660aa80553662e002Marco Nelissen projectionIn[i] = "audio_playlists_map._id AS _id"; 143297e61d89d90a1bd6989a254660aa80553662e002Marco Nelissen } 1433702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1434702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1435702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio_playlists_map, audio"); 1436702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("audio._id = audio_id AND playlist_id = " 1437702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project + uri.getPathSegments().get(3)); 1438702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1439702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1440702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS_ID: 1441702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("audio"); 1442702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id=" + uri.getPathSegments().get(5)); 1443702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1444702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1445702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA: 1446702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("video"); 1447702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1448702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1449702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA_ID: 1450702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("video"); 1451702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id=" + uri.getPathSegments().get(3)); 1452702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1453702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1454b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case VIDEO_THUMBNAILS_ID: 1455b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen hasThumbnailId = true; 1456b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case VIDEO_THUMBNAILS: 1457b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (!queryThumbnail(qb, uri, "videothumbnails", "video_id", hasThumbnailId)) { 1458b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return null; 1459b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1460b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen break; 1461b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1462702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ARTISTS: 1463d9672f4d28ab9038333a0037fe30e386ac0ce610Marco Nelissen if (projectionIn != null && projectionIn.length == 1 && selectionArgs == null 1464ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen && (selection == null || selection.length() == 0) 1465ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen && projectionIn[0].equalsIgnoreCase("count(*)") ) { 1466ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen //Log.i("@@@@", "taking fast path for counting artists"); 1467ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.setTables("audio_meta"); 1468ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen projectionIn[0] = "count(distinct artist_id)"; 1469ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.appendWhere("is_music=1"); 1470ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen } else { 1471ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.setTables("artist_info"); 1472ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen } 1473702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1474702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1475702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ARTISTS_ID: 1476702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("artist_info"); 1477702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id=" + uri.getPathSegments().get(3)); 1478702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1479702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1480702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ARTISTS_ID_ALBUMS: 1481702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String aid = uri.getPathSegments().get(3); 1482acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen qb.setTables("audio LEFT OUTER JOIN album_art ON" + 1483acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen " audio.album_id=album_art.album_id"); 1484acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen qb.appendWhere("is_music=1 AND audio.album_id IN (SELECT album_id FROM " + 1485acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen "artists_albums_map WHERE artist_id = " + 1486acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen aid + ")"); 1487acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen groupBy = "audio.album_id"; 1488702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sArtistAlbumsMap.put(MediaStore.Audio.Albums.NUMBER_OF_SONGS_FOR_ARTIST, 1489acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen "count(CASE WHEN artist_id==" + aid + " THEN 'foo' ELSE NULL END) AS " + 1490702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.Audio.Albums.NUMBER_OF_SONGS_FOR_ARTIST); 1491702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setProjectionMap(sArtistAlbumsMap); 1492702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1493702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1494702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ALBUMS: 1495d9672f4d28ab9038333a0037fe30e386ac0ce610Marco Nelissen if (projectionIn != null && projectionIn.length == 1 && selectionArgs == null 1496ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen && (selection == null || selection.length() == 0) 1497ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen && projectionIn[0].equalsIgnoreCase("count(*)") ) { 1498ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen //Log.i("@@@@", "taking fast path for counting albums"); 1499ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.setTables("audio_meta"); 1500ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen projectionIn[0] = "count(distinct album_id)"; 1501ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.appendWhere("is_music=1"); 1502ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen } else { 1503ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen qb.setTables("album_info"); 1504ea8ed74e997619531921fb4138728b7d65c35089Marco Nelissen } 1505702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1506702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1507702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ALBUMS_ID: 1508702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("album_info"); 1509702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("_id=" + uri.getPathSegments().get(3)); 1510702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1511702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1512702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ALBUMART_ID: 1513702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.setTables("album_art"); 1514702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("album_id=" + uri.getPathSegments().get(3)); 1515702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1516702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1517a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen case AUDIO_SEARCH_LEGACY: 1518a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen Log.w(TAG, "Legacy media search Uri used. Please update your code."); 1519a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // fall through 1520a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen case AUDIO_SEARCH_FANCY: 1521a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen case AUDIO_SEARCH_BASIC: 1522a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen return doAudioSearch(db, qb, uri, projectionIn, selection, selectionArgs, sort, 15234574e03055af60fada50481f2b34e19a687d5866Marco Nelissen table, limit); 1524702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1525b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood case MTP_OBJECTS_ID: 1526b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood qb.appendWhere("_id=" + uri.getPathSegments().get(2)); 1527b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood // fall through 1528b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood case MTP_OBJECTS: 1529b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood qb.setTables("objects"); 1530b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood break; 1531b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 1532702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project default: 1533702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalStateException("Unknown URL: " + uri.toString()); 1534702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1535702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 15364d96d72ea42c2ec41a891f65623270473ae8eebdRay Chen // Log.v(TAG, "query = "+ qb.buildQuery(projectionIn, selection, selectionArgs, groupBy, null, sort, limit)); 1537702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Cursor c = qb.query(db, projectionIn, selection, 15384574e03055af60fada50481f2b34e19a687d5866Marco Nelissen selectionArgs, groupBy, null, sort, limit); 1539b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1540702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (c != null) { 1541702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project c.setNotificationUri(getContext().getContentResolver(), uri); 1542702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1543b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1544702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return c; 1545702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1546702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1547702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private Cursor doAudioSearch(SQLiteDatabase db, SQLiteQueryBuilder qb, 1548702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Uri uri, String[] projectionIn, String selection, 15494574e03055af60fada50481f2b34e19a687d5866Marco Nelissen String[] selectionArgs, String sort, int mode, 15504574e03055af60fada50481f2b34e19a687d5866Marco Nelissen String limit) { 1551702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 155218c787fb045725bf10bf630ac0917a48def9ace5Marco Nelissen String mSearchString = uri.getPath().endsWith("/") ? "" : uri.getLastPathSegment(); 1553702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mSearchString = mSearchString.replaceAll(" ", " ").trim().toLowerCase(); 1554702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1555702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String [] searchWords = mSearchString.length() > 0 ? 1556702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mSearchString.split(" ") : new String[0]; 1557a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen String [] wildcardWords = new String[searchWords.length]; 1558702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Collator col = Collator.getInstance(); 1559702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project col.setStrength(Collator.PRIMARY); 1560702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int len = searchWords.length; 1561702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project for (int i = 0; i < len; i++) { 1562702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Because we match on individual words here, we need to remove words 1563702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // like 'a' and 'the' that aren't part of the keys. 1564a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen wildcardWords[i] = 1565702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project (searchWords[i].equals("a") || searchWords[i].equals("an") || 1566702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project searchWords[i].equals("the")) ? "%" : 1567702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project '%' + MediaStore.Audio.keyFor(searchWords[i]) + '%'; 1568702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1569702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1570a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen String where = ""; 1571a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen for (int i = 0; i < searchWords.length; i++) { 1572a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen if (i == 0) { 1573a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen where = "match LIKE ?"; 1574a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen } else { 1575a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen where += " AND match LIKE ?"; 1576702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1577702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1578702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1579a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen qb.setTables("search"); 1580a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen String [] cols; 1581a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen if (mode == AUDIO_SEARCH_FANCY) { 1582a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen cols = mSearchColsFancy; 1583a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen } else if (mode == AUDIO_SEARCH_BASIC) { 1584a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen cols = mSearchColsBasic; 1585a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen } else { 1586a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen cols = mSearchColsLegacy; 1587702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 15884574e03055af60fada50481f2b34e19a687d5866Marco Nelissen return qb.query(db, cols, where, wildcardWords, null, null, null, limit); 1589702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1590702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1591702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 1592702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public String getType(Uri url) 1593702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project { 1594702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (URI_MATCHER.match(url)) { 1595702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA_ID: 1596702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID: 1597702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID_MEMBERS_ID: 1598702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS_ID: 1599702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA_ID: 160026f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen Cursor c = null; 160126f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen try { 160226f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen c = query(url, MIME_TYPE_PROJECTION, null, null, null); 160326f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen if (c != null && c.getCount() == 1) { 160426f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen c.moveToFirst(); 160526f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen String mimeType = c.getString(1); 160626f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen c.deactivate(); 160726f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen return mimeType; 160826f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen } 160926f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen } finally { 161026f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen if (c != null) { 161126f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen c.close(); 161226f297abf92299b21ad5ddc8f722bd83805e1bc7Ray Chen } 1613702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1614702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1615702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1616702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA: 1617702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_THUMBNAILS: 1618702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Images.Media.CONTENT_TYPE; 1619702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_THUMBNAILS_ID: 1620702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return "image/jpeg"; 1621702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1622702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA: 1623702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID_MEMBERS: 1624702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS: 1625702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Audio.Media.CONTENT_TYPE; 1626702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1627702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES: 1628702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES: 1629702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Audio.Genres.CONTENT_TYPE; 1630702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID: 1631702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES_ID: 1632702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Audio.Genres.ENTRY_CONTENT_TYPE; 1633702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS: 1634702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS: 1635702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Audio.Playlists.CONTENT_TYPE; 1636702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID: 1637702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS_ID: 1638702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Audio.Playlists.ENTRY_CONTENT_TYPE; 1639702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1640702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA: 1641702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Video.Media.CONTENT_TYPE; 1642702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1643702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalStateException("Unknown URL"); 1644702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1645702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1646702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 1647702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Ensures there is a file in the _data column of values, if one isn't 1648702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * present a new file is created. 1649702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 1650702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param initialValues the values passed to insert by the caller 1651702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @return the new values 1652702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 1653702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private ContentValues ensureFile(boolean internal, ContentValues initialValues, 1654702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String preferredExtension, String directoryName) { 1655702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values; 1656702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String file = initialValues.getAsString("_data"); 1657702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (TextUtils.isEmpty(file)) { 1658702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project file = generateFileName(internal, preferredExtension, directoryName); 1659702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values = new ContentValues(initialValues); 1660702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put("_data", file); 1661702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 1662702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values = initialValues; 1663702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1664702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1665702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!ensureFileExists(file)) { 1666702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalStateException("Unable to create new file: " + file); 1667702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1668702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return values; 1669702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1670702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1671702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 1672702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public int bulkInsert(Uri uri, ContentValues values[]) { 1673702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int match = URI_MATCHER.match(uri); 1674702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (match == VOLUMES) { 1675702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return super.bulkInsert(uri, values); 1676702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1677702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DatabaseHelper database = getDatabaseForUri(uri); 1678702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (database == null) { 1679702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException( 1680702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Unknown URI: " + uri); 1681702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1682702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteDatabase db = database.getWritableDatabase(); 1683ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen 1684ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen if (match == AUDIO_PLAYLISTS_ID || match == AUDIO_PLAYLISTS_ID_MEMBERS) { 1685ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen return playlistBulkInsert(db, uri, values); 1686ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen } 1687ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen 1688702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.beginTransaction(); 1689702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int numInserted = 0; 1690702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 1691702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int len = values.length; 1692702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project for (int i = 0; i < len; i++) { 1693702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project insertInternal(uri, values[i]); 1694702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1695702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project numInserted = len; 1696702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.setTransactionSuccessful(); 1697702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 1698702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.endTransaction(); 1699702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1700702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 1701702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return numInserted; 1702702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1703702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1704702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 1705702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public Uri insert(Uri uri, ContentValues initialValues) 1706702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project { 1707702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Uri newUri = insertInternal(uri, initialValues); 1708702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (newUri != null) { 1709702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 1710702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1711702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return newUri; 1712702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1713702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1714ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen private int playlistBulkInsert(SQLiteDatabase db, Uri uri, ContentValues values[]) { 1715ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen DatabaseUtils.InsertHelper helper = 1716ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen new DatabaseUtils.InsertHelper(db, "audio_playlists_map"); 17178b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen int audioidcolidx = helper.getColumnIndex(MediaStore.Audio.Playlists.Members.AUDIO_ID); 17188b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen int playlistididx = helper.getColumnIndex(Audio.Playlists.Members.PLAYLIST_ID); 17198b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen int playorderidx = helper.getColumnIndex(MediaStore.Audio.Playlists.Members.PLAY_ORDER); 17208b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen long playlistId = Long.parseLong(uri.getPathSegments().get(3)); 1721ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen 1722ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen db.beginTransaction(); 1723ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen int numInserted = 0; 1724ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen try { 1725ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen int len = values.length; 1726ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen for (int i = 0; i < len; i++) { 17278b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen helper.prepareForInsert(); 17288b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen // getting the raw Object and converting it long ourselves saves 17298b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen // an allocation (the alternative is ContentValues.getAsLong, which 17308b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen // returns a Long object) 17318b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen long audioid = ((Number) values[i].get( 17328b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen MediaStore.Audio.Playlists.Members.AUDIO_ID)).longValue(); 17338b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen helper.bind(audioidcolidx, audioid); 17348b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen helper.bind(playlistididx, playlistId); 17358b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen // convert to int ourselves to save an allocation. 17368b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen int playorder = ((Number) values[i].get( 17378b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen MediaStore.Audio.Playlists.Members.PLAY_ORDER)).intValue(); 17388b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen helper.bind(playorderidx, playorder); 17398b29060b0563b6a17b21b909bc4a9af14636021cMarco Nelissen helper.execute(); 1740ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen } 1741ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen numInserted = len; 1742ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen db.setTransactionSuccessful(); 1743ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen } finally { 1744ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen db.endTransaction(); 1745ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen helper.close(); 1746ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen } 1747ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen getContext().getContentResolver().notifyChange(uri, null); 1748ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen return numInserted; 1749ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen } 1750ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen 1751b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood private long getParent(SQLiteDatabase db, String path) { 1752b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood int lastSlash = path.lastIndexOf('/'); 1753b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood if (lastSlash > 0) { 1754b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood String parentPath = path.substring(0, lastSlash); 1755b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood if (parentPath.equals(Environment.getExternalStorageDirectory().getAbsolutePath())) { 1756b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood return 0; 1757b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } 1758b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood String [] selargs = { parentPath }; 1759b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood Cursor c = db.query("objects", null, MediaStore.MediaColumns.DATA + "=?", 1760b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood selargs, null, null, null); 1761b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood try { 1762b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood if (c == null || c.getCount() == 0) { 1763b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood // parent isn't in the database - so add it 1764b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood ContentValues values = new ContentValues(); 17651717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood values.put(ObjectColumns.FORMAT, Mtp.Object.FORMAT_ASSOCIATION); 17661717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood values.put(ObjectColumns.DATA, parentPath); 17671717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood values.put(ObjectColumns.PARENT, getParent(db, parentPath)); 17681717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood return db.insert("objects", ObjectColumns.DATE_MODIFIED, values); 1769b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } else { 1770b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood c.moveToFirst(); 1771b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood return c.getLong(0); 1772b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } 1773b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } finally { 1774b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood if (c != null) c.close(); 1775b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } 1776b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } else { 1777b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood return 0; 1778b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } 1779b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } 1780b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 17811717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood private void insertObject(SQLiteDatabase db, ContentValues initialValues, int tableId, long rowId) { 1782b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood String path = initialValues.getAsString(MediaStore.MediaColumns.DATA); 1783b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood if (path == null) { 17841717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood Log.e(TAG, "_data missing in insertObject"); 1785b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood return; 1786b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } 1787b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood ContentValues values = new ContentValues(); 17881717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood values.put(ObjectColumns.DATA, path); 17891717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood values.put(ObjectColumns.MEDIA_TABLE, tableId); 17901717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood values.put(ObjectColumns.MEDIA_ID, rowId); 1791b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 1792b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood Long size = initialValues.getAsLong(MediaStore.MediaColumns.SIZE); 1793b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood if (size == null) { 1794b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood File file = new File(path); 17951717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood values.put(ObjectColumns.SIZE, file.length()); 1796b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } else { 17971717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood values.put(ObjectColumns.SIZE, size); 1798b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } 1799b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 18001717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood Long parent = initialValues.getAsLong(ObjectColumns.PARENT); 1801b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood if (parent == null) { 1802b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood long parentId = getParent(db, path); 18031717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood values.put(ObjectColumns.PARENT, parentId); 1804b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } else { 18051717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood values.put(ObjectColumns.PARENT, parent); 1806b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } 1807b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 18081717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood Integer format = initialValues.getAsInteger(ObjectColumns.FORMAT); 1809b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood if (format == null) { 1810b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood String mimeType = initialValues.getAsString(MediaStore.MediaColumns.MIME_TYPE); 18111717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood values.put(ObjectColumns.FORMAT, MediaFile.getFormatCode(path, mimeType)); 1812b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } else { 18131717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood values.put(ObjectColumns.FORMAT, format); 1814b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } 1815b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 1816b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood Integer modified = initialValues.getAsInteger(MediaStore.MediaColumns.DATE_MODIFIED); 1817b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood if (modified != null) { 18181717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood values.put(ObjectColumns.DATE_MODIFIED, modified); 1819b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } 1820b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 1821b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood rowId = db.insert("objects", "date_modified", values); 18221717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood Log.v(TAG, "insertObject: values="+values+" returned: "+rowId); 18231717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood } 18241717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood 18251717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood private int deleteObject(SQLiteDatabase db, String volume, String table, String where, String[] whereArgs) { 18261717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood // delete from corresponding media table as well 18271717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood Cursor c = db.query("objects", mMediaTableColumns, where, whereArgs, null, null, null); 18281717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood if (c != null && c.moveToNext()) { 18291717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood int mediaTable = c.getInt(1); 18301717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood long mediaId = c.getLong(2); 18311717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood if (mediaId > 0) { 18321717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood // call back to our delete method rather than deleting directly 18331717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood // so notifications will be sent. 18341717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood switch (mediaTable) { 18351717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood case IMAGES_MEDIA: 18361717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood delete(ContentUris.withAppendedId( 18371717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood Images.Media.getContentUri(volume), mediaId), null, null); 18381717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood break; 18391717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood case AUDIO_MEDIA: 18401717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood delete(ContentUris.withAppendedId( 18411717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood Audio.Media.getContentUri(volume), mediaId), null, null); 18421717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood break; 18431717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood case VIDEO_MEDIA: 18441717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood delete(ContentUris.withAppendedId( 18451717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood Video.Media.getContentUri(volume), mediaId), null, null); 18461717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood break; 18471717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood case AUDIO_PLAYLISTS: 18481717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood delete(ContentUris.withAppendedId( 18491717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood Audio.Playlists.getContentUri(volume), mediaId), null, null); 18501717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood break; 18511717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood default: 18521717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood Log.e(TAG, "unknown mediaTable " + mediaTable + " in deleteObject()"); 18531717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood break; 18541717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood } 18551717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood } 18561717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood } 18571717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood return db.delete("objects", where, whereArgs); 1858b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } 1859b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 1860702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private Uri insertInternal(Uri uri, ContentValues initialValues) { 1861702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long rowId; 1862702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int match = URI_MATCHER.match(uri); 1863702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1864b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // Log.v(TAG, "insertInternal: "+uri+", initValues="+initialValues); 1865702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // handle MEDIA_SCANNER before calling getDatabaseForUri() 1866702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (match == MEDIA_SCANNER) { 1867702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mMediaScannerVolume = initialValues.getAsString(MediaStore.MEDIA_SCANNER_VOLUME); 1868702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return MediaStore.getMediaScannerUri(); 1869702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1870702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1871702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Uri newUri = null; 1872702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DatabaseHelper database = getDatabaseForUri(uri); 1873702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (database == null && match != VOLUMES) { 1874702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException( 1875702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Unknown URI: " + uri); 1876702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1877702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteDatabase db = (match == VOLUMES ? null : database.getWritableDatabase()); 1878702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1879702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (initialValues == null) { 1880702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project initialValues = new ContentValues(); 1881702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1882702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1883702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (match) { 1884702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA: { 1885702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = ensureFile(database.mInternal, initialValues, ".jpg", "DCIM/Camera"); 1886702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1887702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(MediaStore.MediaColumns.DATE_ADDED, System.currentTimeMillis() / 1000); 1888702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String data = values.getAsString(MediaColumns.DATA); 1889702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (! values.containsKey(MediaColumns.DISPLAY_NAME)) { 1890702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project computeDisplayName(data, values); 1891702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1892702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project computeBucketValues(data, values); 1893b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen computeTakenTime(values); 1894702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert("images", "name", values); 1895702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1896702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 1897702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId( 1898702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Images.Media.getContentUri(uri.getPathSegments().get(0)), rowId); 18999299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen requestMediaThumbnail(data, newUri, MediaThumbRequest.PRIORITY_NORMAL, 0); 1900702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1901702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1902702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1903702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1904b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // This will be triggered by requestMediaThumbnail (see getThumbnailUri) 1905702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_THUMBNAILS: { 1906b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen ContentValues values = ensureFile(database.mInternal, initialValues, ".jpg", 1907b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "DCIM/.thumbnails"); 1908702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert("thumbnails", "name", values); 1909702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 1910702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(Images.Thumbnails. 1911702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContentUri(uri.getPathSegments().get(0)), rowId); 1912702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1913702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1914702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1915702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1916b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // This is currently only used by MICRO_KIND video thumbnail (see getThumbnailUri) 1917b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case VIDEO_THUMBNAILS: { 1918b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen ContentValues values = ensureFile(database.mInternal, initialValues, ".jpg", 1919b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen "DCIM/.thumbnails"); 1920b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen rowId = db.insert("videothumbnails", "name", values); 1921b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (rowId > 0) { 1922b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen newUri = ContentUris.withAppendedId(Video.Thumbnails. 1923b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen getContentUri(uri.getPathSegments().get(0)), rowId); 1924b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1925b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen break; 1926b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 1927b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 1928702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA: { 1929702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // SQLite Views are read-only, so we need to deconstruct this 1930702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // insert and do inserts into the underlying tables. 1931702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // If doing this here turns out to be a performance bottleneck, 1932702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // consider moving this to native code and using triggers on 1933702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // the view. 1934702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(initialValues); 1935702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1936acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // TODO Remove this and actually store the album_artist in the 1937acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // database. For now this is here so the media scanner can start 1938acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // sending us the album_artist, even though it's not in the db yet. 1939acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen values.remove(MediaStore.Audio.Media.ALBUM_ARTIST); 1940acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen 1941702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Insert the artist into the artist table and remove it from 1942702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // the input values 1943702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Object so = values.get("artist"); 1944702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String s = (so == null ? "" : so.toString()); 1945702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.remove("artist"); 1946702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long artistRowId; 1947702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project HashMap<String, Long> artistCache = database.mArtistCache; 194859948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen String path = values.getAsString("_data"); 1949702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized(artistCache) { 1950702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Long temp = artistCache.get(s); 1951702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (temp == null) { 1952702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project artistRowId = getKeyIdForName(db, "artists", "artist_key", "artist", 1953a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen s, s, path, 0, null, artistCache, uri); 1954702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 1955702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project artistRowId = temp.longValue(); 1956702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1957702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1958a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen String artist = s; 1959702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1960702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Do the same for the album field 1961702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project so = values.get("album"); 1962702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project s = (so == null ? "" : so.toString()); 1963702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.remove("album"); 1964702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long albumRowId; 1965702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project HashMap<String, Long> albumCache = database.mAlbumCache; 1966702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized(albumCache) { 196759948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen int albumhash = path.substring(0, path.lastIndexOf('/')).hashCode(); 196859948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen String cacheName = s + albumhash; 196959948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen Long temp = albumCache.get(cacheName); 1970702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (temp == null) { 1971702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project albumRowId = getKeyIdForName(db, "albums", "album_key", "album", 1972a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen s, cacheName, path, albumhash, artist, albumCache, uri); 1973702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 1974702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project albumRowId = temp; 1975702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1976702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1977702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1978702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put("artist_id", Integer.toString((int)artistRowId)); 1979702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put("album_id", Integer.toString((int)albumRowId)); 1980702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project so = values.getAsString("title"); 1981702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project s = (so == null ? "" : so.toString()); 1982702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put("title_key", MediaStore.Audio.keyFor(s)); 1983358cfed9391de9b39ecb2a3dbefcf5e392915954Marco Nelissen // do a final trim of the title, in case it started with the special 1984358cfed9391de9b39ecb2a3dbefcf5e392915954Marco Nelissen // "sort first" character (ascii \001) 1985358cfed9391de9b39ecb2a3dbefcf5e392915954Marco Nelissen values.remove("title"); 1986358cfed9391de9b39ecb2a3dbefcf5e392915954Marco Nelissen values.put("title", s.trim()); 1987702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1988702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project computeDisplayName(values.getAsString("_data"), values); 1989702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(MediaStore.MediaColumns.DATE_ADDED, System.currentTimeMillis() / 1000); 1990702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1991702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert("audio_meta", "duration", values); 1992702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 1993702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(Audio.Media.getContentUri(uri.getPathSegments().get(0)), rowId); 1994702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1995702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 1996702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 1997702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 1998702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES: { 1999702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Long audioId = Long.parseLong(uri.getPathSegments().get(2)); 2000702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(initialValues); 2001702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(Audio.Genres.Members.AUDIO_ID, audioId); 2002ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen rowId = db.insert("audio_genres_map", "genre_id", values); 2003702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 2004702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(uri, rowId); 2005702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2006702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2007702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2008702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2009702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS: { 2010702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Long audioId = Long.parseLong(uri.getPathSegments().get(2)); 2011702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(initialValues); 2012702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(Audio.Playlists.Members.AUDIO_ID, audioId); 2013702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert("audio_playlists_map", "playlist_id", 2014702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values); 2015702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 2016702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(uri, rowId); 2017702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2018702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2019702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2020702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2021702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES: { 2022702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert("audio_genres", "audio_id", initialValues); 2023702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 2024702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(Audio.Genres.getContentUri(uri.getPathSegments().get(0)), rowId); 2025702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2026702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2027702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2028702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2029702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID_MEMBERS: { 2030702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Long genreId = Long.parseLong(uri.getPathSegments().get(3)); 2031702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(initialValues); 2032702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(Audio.Genres.Members.GENRE_ID, genreId); 2033702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert("audio_genres_map", "genre_id", values); 2034702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 2035702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(uri, rowId); 2036702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2037702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2038702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2039702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2040702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS: { 2041702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(initialValues); 2042702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(MediaStore.Audio.Playlists.DATE_ADDED, System.currentTimeMillis() / 1000); 2043702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert("audio_playlists", "name", initialValues); 2044702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 2045702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(Audio.Playlists.getContentUri(uri.getPathSegments().get(0)), rowId); 2046702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2047702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2048702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2049702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2050702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID: 2051702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS: { 2052702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Long playlistId = Long.parseLong(uri.getPathSegments().get(3)); 2053702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(initialValues); 2054702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(Audio.Playlists.Members.PLAYLIST_ID, playlistId); 2055ccf3e3c938fa9777cb6297b4e910cb6a58558671Marco Nelissen rowId = db.insert("audio_playlists_map", "playlist_id", values); 2056702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 2057702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(uri, rowId); 2058702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2059702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2060702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2061702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2062702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA: { 2063702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = ensureFile(database.mInternal, initialValues, ".3gp", "video"); 2064702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String data = values.getAsString("_data"); 2065702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project computeDisplayName(data, values); 2066702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project computeBucketValues(data, values); 2067702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put(MediaStore.MediaColumns.DATE_ADDED, System.currentTimeMillis() / 1000); 2068498b62c2912302a23532c73a028a7684c5df33caRay Chen computeTakenTime(values); 2069702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert("video", "artist", values); 2070702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 2071b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen newUri = ContentUris.withAppendedId(Video.Media.getContentUri( 2072b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen uri.getPathSegments().get(0)), rowId); 20739299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen requestMediaThumbnail(data, newUri, MediaThumbRequest.PRIORITY_NORMAL, 0); 2074702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2075702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2076702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2077702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2078702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ALBUMART: 2079702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (database.mInternal) { 2080702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException("no internal album art allowed"); 2081702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2082702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = null; 2083702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 2084702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values = ensureFile(false, initialValues, "", ALBUM_THUMB_FOLDER); 2085702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } catch (IllegalStateException ex) { 2086702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // probably no more room to store albumthumbs 2087702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values = initialValues; 2088702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2089702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert("album_art", "_data", values); 2090702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 2091702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newUri = ContentUris.withAppendedId(uri, rowId); 2092702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2093702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2094702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2095702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VOLUMES: 2096702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return attachVolume(initialValues.getAsString("name")); 2097702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2098702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project default: 2099702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException("Invalid URI " + uri); 2100702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2101702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2102b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood if (rowId > 0 && 2103b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood (match == IMAGES_MEDIA || 2104b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood match == AUDIO_MEDIA || 2105b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood match == VIDEO_MEDIA || 2106b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood match == AUDIO_PLAYLISTS)) { 21071717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood insertObject(db, initialValues, match, rowId); 2108b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood } 2109b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 2110702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return newUri; 2111702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2112702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2113cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen @Override 2114cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) 2115cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen throws OperationApplicationException { 2116cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen 2117cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen // The operations array provides no overall information about the URI(s) being operated 2118cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen // on, so begin a transaction for ALL of the databases. 2119cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen DatabaseHelper ihelper = getDatabaseForUri(MediaStore.Audio.Media.INTERNAL_CONTENT_URI); 2120cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen DatabaseHelper ehelper = getDatabaseForUri(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI); 2121cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen SQLiteDatabase idb = ihelper.getWritableDatabase(); 2122cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen idb.beginTransaction(); 2123cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen SQLiteDatabase edb = null; 2124cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen if (ehelper != null) { 2125cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen edb = ehelper.getWritableDatabase(); 2126cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen edb.beginTransaction(); 2127cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen } 2128cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen try { 2129cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen ContentProviderResult[] result = super.applyBatch(operations); 2130cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen idb.setTransactionSuccessful(); 2131cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen if (edb != null) { 2132cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen edb.setTransactionSuccessful(); 2133cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen } 2134cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen // Rather than sending targeted change notifications for every Uri 2135cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen // affected by the batch operation, just invalidate the entire internal 2136cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen // and external name space. 2137cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen ContentResolver res = getContext().getContentResolver(); 2138cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen res.notifyChange(Uri.parse("content://media/"), null); 2139cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen return result; 2140cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen } finally { 2141cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen idb.endTransaction(); 2142cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen if (edb != null) { 2143cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen edb.endTransaction(); 2144cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen } 2145cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen } 2146cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen } 2147cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen 2148cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen 21499299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen private MediaThumbRequest requestMediaThumbnail(String path, Uri uri, int priority, long magic) { 2150b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen synchronized (mMediaThumbQueue) { 2151e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen MediaThumbRequest req = null; 2152e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen try { 2153e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen req = new MediaThumbRequest( 21549299727714ad25618a1a77eeca7f1e9c72f1e510Ray Chen getContext().getContentResolver(), path, uri, priority, magic); 2155e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen mMediaThumbQueue.add(req); 2156e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen // Trigger the handler. 2157e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen Message msg = mThumbHandler.obtainMessage(IMAGE_THUMB); 2158e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen msg.sendToTarget(); 2159e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen } catch (Throwable t) { 2160e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen Log.w(TAG, t); 2161e7219b83c17d75151746d6cad1b61d447910ae92Ray Chen } 2162b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen return req; 2163b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 2164b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 2165b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 2166702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private String generateFileName(boolean internal, String preferredExtension, String directoryName) 2167702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project { 2168702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // create a random file 2169702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String name = String.valueOf(System.currentTimeMillis()); 2170702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2171702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (internal) { 2172702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException("Writing to internal storage is not supported."); 2173702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project// return Environment.getDataDirectory() 2174702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project// + "/" + directoryName + "/" + name + preferredExtension; 2175702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 2176702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Environment.getExternalStorageDirectory() 2177702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project + "/" + directoryName + "/" + name + preferredExtension; 2178702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2179702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2180702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2181702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private boolean ensureFileExists(String path) { 2182702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File file = new File(path); 2183702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (file.exists()) { 2184702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return true; 2185702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 2186702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // we will not attempt to create the first directory in the path 2187702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // (for example, do not create /sdcard if the SD card is not mounted) 2188702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int secondSlash = path.indexOf('/', 1); 2189702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (secondSlash < 1) return false; 2190702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String directoryPath = path.substring(0, secondSlash); 2191702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File directory = new File(directoryPath); 2192702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!directory.exists()) 2193702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return false; 2194702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project file.getParentFile().mkdirs(); 2195702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 2196702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return file.createNewFile(); 2197702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } catch(IOException ioe) { 2198702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Log.e(TAG, "File creation failed", ioe); 2199702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2200702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return false; 2201702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2202702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2203702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2204702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final class GetTableAndWhereOutParameter { 2205702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public String table; 2206702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public String where; 2207702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2208702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2209702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project static final GetTableAndWhereOutParameter sGetTableAndWhereParam = 2210702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project new GetTableAndWhereOutParameter(); 2211702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2212702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private void getTableAndWhere(Uri uri, int match, String userWhere, 2213702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project GetTableAndWhereOutParameter out) { 2214702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String where = null; 2215702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (match) { 22169f02f449f6951b15bb9daaa3fc6e1d648b36b08aGoodwin case IMAGES_MEDIA: 22179f02f449f6951b15bb9daaa3fc6e1d648b36b08aGoodwin out.table = "images"; 22189f02f449f6951b15bb9daaa3fc6e1d648b36b08aGoodwin break; 22199f02f449f6951b15bb9daaa3fc6e1d648b36b08aGoodwin 2220702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA_ID: 2221702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "images"; 2222702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "_id = " + uri.getPathSegments().get(3); 2223702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2224702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2225b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case IMAGES_THUMBNAILS_ID: 2226b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen where = "_id=" + uri.getPathSegments().get(3); 2227b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case IMAGES_THUMBNAILS: 2228b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen out.table = "thumbnails"; 2229b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen break; 2230b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 2231702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA: 2232702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio"; 2233702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2234702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2235702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID: 2236702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio"; 2237702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "_id=" + uri.getPathSegments().get(3); 2238702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2239702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2240702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES: 2241702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_genres"; 2242702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "audio_id=" + uri.getPathSegments().get(3); 2243702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2244702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2245702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_GENRES_ID: 2246702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_genres"; 2247702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "audio_id=" + uri.getPathSegments().get(3) + 2248702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " AND genre_id=" + uri.getPathSegments().get(5); 2249702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2250702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2251702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS: 2252702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_playlists"; 2253702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "audio_id=" + uri.getPathSegments().get(3); 2254702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2255702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2256702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID_PLAYLISTS_ID: 2257702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_playlists"; 2258702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "audio_id=" + uri.getPathSegments().get(3) + 2259702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " AND playlists_id=" + uri.getPathSegments().get(5); 2260702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2261702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2262702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES: 2263702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_genres"; 2264702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2265702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2266702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID: 2267702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_genres"; 2268702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "_id=" + uri.getPathSegments().get(3); 2269702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2270702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2271702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID_MEMBERS: 2272702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_genres"; 2273702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "genre_id=" + uri.getPathSegments().get(3); 2274702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2275702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2276702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_GENRES_ID_MEMBERS_ID: 2277702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_genres"; 2278702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "genre_id=" + uri.getPathSegments().get(3) + 2279702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " AND audio_id =" + uri.getPathSegments().get(5); 2280702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2281702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2282702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS: 2283702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_playlists"; 2284702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2285702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2286702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID: 2287702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_playlists"; 2288702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "_id=" + uri.getPathSegments().get(3); 2289702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2290702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2291702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS: 2292702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_playlists_map"; 2293702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "playlist_id=" + uri.getPathSegments().get(3); 2294702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2295702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2296702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_PLAYLISTS_ID_MEMBERS_ID: 2297702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "audio_playlists_map"; 2298702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "playlist_id=" + uri.getPathSegments().get(3) + 2299702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project " AND _id=" + uri.getPathSegments().get(5); 2300702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2301702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2302702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_ALBUMART_ID: 2303702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "album_art"; 2304702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "album_id=" + uri.getPathSegments().get(3); 2305702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2306702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2307702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA: 2308702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "video"; 2309702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2310702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2311702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA_ID: 2312702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.table = "video"; 2313702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project where = "_id=" + uri.getPathSegments().get(3); 2314702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2315702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2316b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case VIDEO_THUMBNAILS_ID: 2317b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen where = "_id=" + uri.getPathSegments().get(3); 2318b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen case VIDEO_THUMBNAILS: 2319b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen out.table = "videothumbnails"; 2320b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen break; 2321b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 23221717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood case MTP_OBJECTS_ID: 23231717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood where = "_id=" + uri.getPathSegments().get(2); 23241717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood case MTP_OBJECTS: 23251717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood out.table = "objects"; 23261717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood break; 23271717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood 2328702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project default: 2329702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException( 2330702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Unknown or unsupported URL: " + uri.toString()); 2331702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2332702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2333702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Add in the user requested WHERE clause, if needed 2334702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!TextUtils.isEmpty(userWhere)) { 2335702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!TextUtils.isEmpty(where)) { 2336702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.where = where + " AND (" + userWhere + ")"; 2337702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 2338702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.where = userWhere; 2339702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2340702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 2341702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project out.where = where; 2342702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2343702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2344702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2345702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 2346702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public int delete(Uri uri, String userWhere, String[] whereArgs) { 2347702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int count; 2348702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int match = URI_MATCHER.match(uri); 2349702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2350702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // handle MEDIA_SCANNER before calling getDatabaseForUri() 2351702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (match == MEDIA_SCANNER) { 2352702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (mMediaScannerVolume == null) { 2353702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return 0; 2354702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2355702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mMediaScannerVolume = null; 2356702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return 1; 2357702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2358702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2359702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (match != VOLUMES_ID) { 2360702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DatabaseHelper database = getDatabaseForUri(uri); 2361702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (database == null) { 2362702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException( 2363702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Unknown URI: " + uri); 2364702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2365702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteDatabase db = database.getWritableDatabase(); 2366702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2367702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized (sGetTableAndWhereParam) { 2368702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getTableAndWhere(uri, match, userWhere, sGetTableAndWhereParam); 2369702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (match) { 2370702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA: 2371702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID: 2372702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count = db.delete("audio_meta", 2373702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sGetTableAndWhereParam.where, whereArgs); 2374702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 23751717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood case MTP_OBJECTS: 23761717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood throw new UnsupportedOperationException( 23771717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood "Deleting multiple objects via MTP not supported"); 23781717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood case MTP_OBJECTS_ID: 23791717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood // return here to avoid calling notifyChange() 23801717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood return deleteObject(db, uri.getPathSegments().get(0), 23811717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood sGetTableAndWhereParam.table, 23821717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood sGetTableAndWhereParam.where, whereArgs); 2383702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project default: 2384702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count = db.delete(sGetTableAndWhereParam.table, 2385702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sGetTableAndWhereParam.where, whereArgs); 2386702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2387702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2388702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 2389702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2390702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 2391702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project detachVolume(uri); 2392702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count = 1; 2393702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2394702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2395702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return count; 2396702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2397702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2398702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 2399702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public int update(Uri uri, ContentValues initialValues, String userWhere, 2400702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String[] whereArgs) { 2401702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int count; 2402b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen // Log.v(TAG, "update for uri="+uri+", initValues="+initialValues); 2403702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int match = URI_MATCHER.match(uri); 2404702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DatabaseHelper database = getDatabaseForUri(uri); 2405702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (database == null) { 2406702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException( 2407702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Unknown URI: " + uri); 2408702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2409702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteDatabase db = database.getWritableDatabase(); 2410702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2411702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized (sGetTableAndWhereParam) { 2412702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getTableAndWhere(uri, match, userWhere, sGetTableAndWhereParam); 2413702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2414702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (match) { 2415702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA: 2416702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case AUDIO_MEDIA_ID: 2417702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project { 2418702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(initialValues); 2419acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // TODO Remove this and actually store the album_artist in the 2420acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // database. For now this is here so the media scanner can start 2421acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen // sending us the album_artist, even though it's not in the db yet. 2422acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen values.remove(MediaStore.Audio.Media.ALBUM_ARTIST); 242307656cccafca173c6ab54c681a69538dcf0516ddMarco Nelissen 2424702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Insert the artist into the artist table and remove it from 2425702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // the input values 2426a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen String artist = values.getAsString("artist"); 24276006570c27674c47fcea8e674832a715cfd653eaMarco Nelissen values.remove("artist"); 2428a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen if (artist != null) { 2429702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long artistRowId; 2430702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project HashMap<String, Long> artistCache = database.mArtistCache; 2431702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized(artistCache) { 2432a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen Long temp = artistCache.get(artist); 2433702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (temp == null) { 2434acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen artistRowId = getKeyIdForName(db, "artists", "artist_key", "artist", 2435acfb9a20e1131f7dc2521331ee3856c8586c35bdMarco Nelissen artist, artist, null, 0, null, artistCache, uri); 2436702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 2437702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project artistRowId = temp.longValue(); 2438702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2439702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2440702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put("artist_id", Integer.toString((int)artistRowId)); 2441702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2442702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 244359948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // Do the same for the album field. 2444a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen String so = values.getAsString("album"); 24456006570c27674c47fcea8e674832a715cfd653eaMarco Nelissen values.remove("album"); 2446702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (so != null) { 244759948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen String path = values.getAsString("_data"); 244859948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen int albumHash = 0; 244959948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen if (path == null) { 245059948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // If the path is null, we don't have a hash for the file in question. 245159948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen Log.w(TAG, "Update without specified path."); 245259948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen } else { 245359948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen albumHash = path.substring(0, path.lastIndexOf('/')).hashCode(); 245459948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen } 2455702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String s = so.toString(); 2456702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long albumRowId; 2457702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project HashMap<String, Long> albumCache = database.mAlbumCache; 2458702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized(albumCache) { 245959948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen String cacheName = s + albumHash; 246059948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen Long temp = albumCache.get(cacheName); 2461702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (temp == null) { 2462702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project albumRowId = getKeyIdForName(db, "albums", "album_key", "album", 2463a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen s, cacheName, path, albumHash, artist, albumCache, uri); 2464702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 2465702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project albumRowId = temp.longValue(); 2466702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2467702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2468702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put("album_id", Integer.toString((int)albumRowId)); 2469702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2470702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2471702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // don't allow the title_key field to be updated directly 2472702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.remove("title_key"); 2473702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // If the title field is modified, update the title_key 2474702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project so = values.getAsString("title"); 2475702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (so != null) { 2476702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String s = so.toString(); 2477702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.put("title_key", MediaStore.Audio.keyFor(s)); 2478e96c1d9637e89b5f99c7002fd06f7f35a9164849Marco Nelissen // do a final trim of the title, in case it started with the special 2479e96c1d9637e89b5f99c7002fd06f7f35a9164849Marco Nelissen // "sort first" character (ascii \001) 2480e96c1d9637e89b5f99c7002fd06f7f35a9164849Marco Nelissen values.remove("title"); 2481e96c1d9637e89b5f99c7002fd06f7f35a9164849Marco Nelissen values.put("title", s.trim()); 2482702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2483702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2484702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count = db.update("audio_meta", values, sGetTableAndWhereParam.where, 2485702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project whereArgs); 2486702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2487702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2488702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA: 2489702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case IMAGES_MEDIA_ID: 2490702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA: 2491702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case VIDEO_MEDIA_ID: 2492702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project { 2493702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues values = new ContentValues(initialValues); 2494702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Don't allow bucket id or display name to be updated directly. 2495702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // The same names are used for both images and table columns, so 2496702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // we use the ImageColumns constants here. 2497702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.remove(ImageColumns.BUCKET_ID); 2498702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project values.remove(ImageColumns.BUCKET_DISPLAY_NAME); 2499702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // If the data is being modified update the bucket values 2500702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String data = values.getAsString(MediaColumns.DATA); 2501702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (data != null) { 2502702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project computeBucketValues(data, values); 2503702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2504b9842a182cb761dbcac82ff2024e38d0cd9a9e73Ray Chen computeTakenTime(values); 2505702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count = db.update(sGetTableAndWhereParam.table, values, 2506702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sGetTableAndWhereParam.where, whereArgs); 250701a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen // if this is a request from MediaScanner, DATA should contains file path 250801a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen // we only process update request from media scanner, otherwise the requests 250901a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen // could be duplicate. 251001a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen if (count > 0 && values.getAsString(MediaStore.MediaColumns.DATA) != null) { 251101a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen Cursor c = db.query(sGetTableAndWhereParam.table, 251201a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen READY_FLAG_PROJECTION, sGetTableAndWhereParam.where, 251301a6f2f96c5b483f5281f6d3066380a129c06021Ray Chen whereArgs, null, null, null); 2514b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen if (c != null) { 2515216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen try { 2516216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen while (c.moveToNext()) { 2517216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen long magic = c.getLong(2); 2518216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen if (magic == 0) { 2519216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen requestMediaThumbnail(c.getString(1), uri, 2520216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen MediaThumbRequest.PRIORITY_NORMAL, 0); 2521216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen } 2522b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 2523216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen } finally { 2524216ec3f0643cd9a9ea9daf96a0ed98d1cc4b1751Marco Nelissen c.close(); 2525b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 2526b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 2527b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen } 2528702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2529702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2530f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen 2531f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen case AUDIO_PLAYLISTS_ID_MEMBERS_ID: 2532f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen String moveit = uri.getQueryParameter("move"); 2533f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen if (moveit != null) { 2534f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen String key = MediaStore.Audio.Playlists.Members.PLAY_ORDER; 2535f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen if (initialValues.containsKey(key)) { 2536f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen int newpos = initialValues.getAsInteger(key); 2537f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen List <String> segments = uri.getPathSegments(); 2538f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen long playlist = Long.valueOf(segments.get(3)); 2539f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen int oldpos = Integer.valueOf(segments.get(5)); 2540f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen return movePlaylistEntry(db, playlist, oldpos, newpos); 2541f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } 2542f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen throw new IllegalArgumentException("Need to specify " + key + 2543f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " when using 'move' parameter"); 2544f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } 2545f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen // fall through 2546702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project default: 2547702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project count = db.update(sGetTableAndWhereParam.table, initialValues, 2548702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project sGetTableAndWhereParam.where, whereArgs); 2549702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 2550702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2551702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2552cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen // in a transaction, the code that began the transaction should be taking 2553cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen // care of notifications once it ends the transaction successfully 2554cb0c5a6863b073d142b1fd3b4168cd665b72ae80Marco Nelissen if (count > 0 && !db.inTransaction()) { 2555702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 2556702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2557702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return count; 2558702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2559702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2560f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen private int movePlaylistEntry(SQLiteDatabase db, long playlist, int from, int to) { 2561f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen if (from == to) { 2562f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen return 0; 2563f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } 2564f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen db.beginTransaction(); 2565f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen try { 2566f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen int numlines = 0; 2567f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen db.execSQL("UPDATE audio_playlists_map SET play_order=-1" + 2568f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " WHERE play_order=" + from + 2569f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " AND playlist_id=" + playlist); 2570f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen // We could just run both of the next two statements, but only one of 2571f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen // of them will actually do anything, so might as well skip the compile 2572f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen // and execute steps. 2573f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen if (from < to) { 2574f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen db.execSQL("UPDATE audio_playlists_map SET play_order=play_order-1" + 2575f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " WHERE play_order<=" + to + " AND play_order>" + from + 2576f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " AND playlist_id=" + playlist); 2577f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen numlines = to - from + 1; 2578f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } else { 2579f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen db.execSQL("UPDATE audio_playlists_map SET play_order=play_order+1" + 2580f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " WHERE play_order>=" + to + " AND play_order<" + from + 2581f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " AND playlist_id=" + playlist); 2582f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen numlines = from - to + 1; 2583f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } 2584f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen db.execSQL("UPDATE audio_playlists_map SET play_order=" + to + 2585f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen " WHERE play_order=-1 AND playlist_id=" + playlist); 2586f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen db.setTransactionSuccessful(); 2587f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen Uri uri = MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI 2588f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen .buildUpon().appendEncodedPath(String.valueOf(playlist)).build(); 2589f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen getContext().getContentResolver().notifyChange(uri, null); 2590f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen return numlines; 2591f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } finally { 2592f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen db.endTransaction(); 2593f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } 2594f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen } 2595f5f9eca3e7237c0aa12ea9e58bd980af041adbc4Marco Nelissen 2596702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final String[] openFileColumns = new String[] { 2597702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.MediaColumns.DATA, 2598702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project }; 2599702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2600702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project @Override 2601702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project public ParcelFileDescriptor openFile(Uri uri, String mode) 2602702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throws FileNotFoundException { 260371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen 2604702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ParcelFileDescriptor pfd = null; 260571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen 260671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (URI_MATCHER.match(uri) == AUDIO_ALBUMART_FILE_ID) { 260771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // get album art for the specified media file 260871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen DatabaseHelper database = getDatabaseForUri(uri); 260971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (database == null) { 261071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen throw new IllegalStateException("Couldn't open database for " + uri); 261171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 261271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen SQLiteDatabase db = database.getReadableDatabase(); 261371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 261471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen int songid = Integer.parseInt(uri.getPathSegments().get(3)); 261571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen qb.setTables("audio_meta"); 261671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen qb.appendWhere("_id=" + songid); 261771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen Cursor c = qb.query(db, 261871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen new String [] { 261971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen MediaStore.Audio.Media.DATA, 262071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen MediaStore.Audio.Media.ALBUM_ID }, 262171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen null, null, null, null, null); 262271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (c.moveToFirst()) { 262371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen String audiopath = c.getString(0); 262471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen int albumid = c.getInt(1); 262571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // Try to get existing album art for this album first, which 262671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // could possibly have been obtained from a different file. 262771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // If that fails, try to get it from this specific file. 262871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen Uri newUri = ContentUris.withAppendedId(ALBUMART_URI, albumid); 262971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen try { 263071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen pfd = openFile(newUri, mode); // recursive call 263171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } catch (FileNotFoundException ex) { 263271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // That didn't work, now try to get it from the specific file 263371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen pfd = getThumb(db, audiopath, albumid, null); 263471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 263571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 263671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen c.close(); 263771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen return pfd; 263871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 263971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen 2640702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 2641702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project pfd = openFileHelper(uri, mode); 2642702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } catch (FileNotFoundException ex) { 264371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (mode.contains("w")) { 264471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // if the file couldn't be created, we shouldn't extract album art 264571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen throw ex; 264671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 264771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen 2648702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (URI_MATCHER.match(uri) == AUDIO_ALBUMART_ID) { 2649702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Tried to open an album art file which does not exist. Regenerate. 2650702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DatabaseHelper database = getDatabaseForUri(uri); 2651702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (database == null) { 2652702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw ex; 2653702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2654702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteDatabase db = database.getReadableDatabase(); 2655702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 2656702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int albumid = Integer.parseInt(uri.getPathSegments().get(3)); 265771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen qb.setTables("audio_meta"); 2658702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project qb.appendWhere("album_id=" + albumid); 2659702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Cursor c = qb.query(db, 2660702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project new String [] { 2661702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.Audio.Media.DATA }, 2662702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project null, null, null, null, null); 266371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (c.moveToFirst()) { 2664702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String audiopath = c.getString(0); 266571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen pfd = getThumb(db, audiopath, albumid, uri); 2666702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2667702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project c.close(); 2668702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 266971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (pfd == null) { 267071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen throw ex; 267171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 2672702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2673702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return pfd; 2674702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2675702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2676702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private class ThumbData { 2677702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project SQLiteDatabase db; 2678702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String path; 2679702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long album_id; 2680702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Uri albumart_uri; 2681702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2682702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2683a9c4e330dacb37cfffa9c00f7da83cafde4accefMarco Nelissen private void makeThumbAsync(SQLiteDatabase db, String path, long album_id) { 26848a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber synchronized (mPendingThumbs) { 26858a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (mPendingThumbs.contains(path)) { 26868a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // There's already a request to make an album art thumbnail 26878a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // for this audio file in the queue. 26888a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber return; 26898a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 26908a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 26918a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber mPendingThumbs.add(path); 26928a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 26938a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 2694702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ThumbData d = new ThumbData(); 2695702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project d.db = db; 2696702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project d.path = path; 2697702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project d.album_id = album_id; 2698a9c4e330dacb37cfffa9c00f7da83cafde4accefMarco Nelissen d.albumart_uri = ContentUris.withAppendedId(mAlbumArtBaseUri, album_id); 26998a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 27008a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // Instead of processing thumbnail requests in the order they were 27018a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // received we instead process them stack-based, i.e. LIFO. 27028a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // The idea behind this is that the most recently requested thumbnails 27038a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // are most likely the ones still in the user's view, whereas those 27048a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // requested earlier may have already scrolled off. 27058a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber synchronized (mThumbRequestStack) { 27068a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber mThumbRequestStack.push(d); 27078a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 27088a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 27098a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // Trigger the handler. 2710b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen Message msg = mThumbHandler.obtainMessage(ALBUM_THUMB); 2711702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project msg.sendToTarget(); 2712702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2713702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 27148a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // Extract compressed image data from the audio file itself or, if that fails, 27158a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // look for a file "AlbumArt.jpg" in the containing directory. 27168a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber private static byte[] getCompressedAlbumArt(Context context, String path) { 27178a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber byte[] compressed = null; 2718702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2719702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 2720702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File f = new File(path); 2721702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ParcelFileDescriptor pfd = ParcelFileDescriptor.open(f, 2722702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ParcelFileDescriptor.MODE_READ_ONLY); 2723702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 27248a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber MediaScanner scanner = new MediaScanner(context); 27258a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber compressed = scanner.extractAlbumArt(pfd.getFileDescriptor()); 2726702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project pfd.close(); 2727702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2728d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // If no embedded art exists, look for a suitable image file in the 27293f9c37ea95a3bdf5f84dc79eb199256c4deda29aMarco Nelissen // same directory as the media file, except if that directory is 27303f9c37ea95a3bdf5f84dc79eb199256c4deda29aMarco Nelissen // is the root directory of the sd card or the download directory. 2731d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // We look for, in order of preference: 2732d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // 0 AlbumArt.jpg 2733d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // 1 AlbumArt*Large.jpg 2734d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // 2 Any other jpg image with 'albumart' anywhere in the name 2735d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // 3 Any other jpg image 2736d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // 4 any other png image 27378a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (compressed == null && path != null) { 2738702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int lastSlash = path.lastIndexOf('/'); 2739702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (lastSlash > 0) { 2740d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen 27413f9c37ea95a3bdf5f84dc79eb199256c4deda29aMarco Nelissen String artPath = path.substring(0, lastSlash); 27423f9c37ea95a3bdf5f84dc79eb199256c4deda29aMarco Nelissen String sdroot = Environment.getExternalStorageDirectory().getAbsolutePath(); 27430fe3097230b324e65a874bd7c8c0f430d2fb8cbeMarco Nelissen String dwndir = Environment.getExternalStoragePublicDirectory( 27442f07f572bc574b685b491ee07a6209c7f2dcb13fMarco Nelissen Environment.DIRECTORY_DOWNLOADS).getAbsolutePath(); 2745d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen 2746d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen String bestmatch = null; 2747d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen synchronized (sFolderArtMap) { 2748d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen if (sFolderArtMap.containsKey(artPath)) { 2749d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = sFolderArtMap.get(artPath); 2750ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen } else if (!artPath.equalsIgnoreCase(sdroot) && 2751ad189fb4a03da9a9ef4125207421ad755269d6f8Marco Nelissen !artPath.equalsIgnoreCase(dwndir)) { 2752d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen File dir = new File(artPath); 2753d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen String [] entrynames = dir.list(); 2754d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen if (entrynames == null) { 2755d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen return null; 2756d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } 2757d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = null; 2758d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen int matchlevel = 1000; 2759d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen for (int i = entrynames.length - 1; i >=0; i--) { 2760d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen String entry = entrynames[i].toLowerCase(); 2761d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen if (entry.equals("albumart.jpg")) { 2762d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = entrynames[i]; 2763d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen break; 2764d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } else if (entry.startsWith("albumart") 2765d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen && entry.endsWith("large.jpg") 2766d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen && matchlevel > 1) { 2767d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = entrynames[i]; 2768d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen matchlevel = 1; 2769d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } else if (entry.contains("albumart") 2770d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen && entry.endsWith(".jpg") 2771d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen && matchlevel > 2) { 2772d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = entrynames[i]; 2773d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen matchlevel = 2; 2774d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } else if (entry.endsWith(".jpg") && matchlevel > 3) { 2775d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = entrynames[i]; 2776d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen matchlevel = 3; 2777d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } else if (entry.endsWith(".png") && matchlevel > 4) { 2778d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen bestmatch = entrynames[i]; 2779d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen matchlevel = 4; 2780d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } 2781d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } 2782d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen // note that this may insert null if no album art was found 2783d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen sFolderArtMap.put(artPath, bestmatch); 2784d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } 2785d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } 2786d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen 2787d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen if (bestmatch != null) { 27883f9c37ea95a3bdf5f84dc79eb199256c4deda29aMarco Nelissen File file = new File(artPath, bestmatch); 2789d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen if (file.exists()) { 2790d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen compressed = new byte[(int)file.length()]; 2791d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen FileInputStream stream = null; 2792d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen try { 2793d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen stream = new FileInputStream(file); 2794d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen stream.read(compressed); 2795d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } catch (IOException ex) { 2796d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen compressed = null; 2797d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } finally { 2798d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen if (stream != null) { 2799d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen stream.close(); 2800d239857cc84099d32b0439993c4e3eef2129f771Marco Nelissen } 2801702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2802702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2803702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2804702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2805702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 28068a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } catch (IOException e) { 28078a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 2808702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 28098a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber return compressed; 28108a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 2811702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 28128a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // Return a URI to write the album art to and update the database as necessary. 28138a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber Uri getAlbumArtOutputUri(SQLiteDatabase db, long album_id, Uri albumart_uri) { 28148a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber Uri out = null; 28158a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // TODO: this could be done more efficiently with a call to db.replace(), which 28168a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // replaces or inserts as needed, making it unnecessary to query() first. 28178a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (albumart_uri != null) { 28188a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber Cursor c = query(albumart_uri, new String [] { "_data" }, 28198a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber null, null, null); 282071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (c.moveToFirst()) { 28218a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber String albumart_path = c.getString(0); 28228a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (ensureFileExists(albumart_path)) { 28238a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber out = albumart_uri; 2824702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 282571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } else { 282671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen albumart_uri = null; 2827702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 28288a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber c.close(); 282971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 283071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (albumart_uri == null){ 28318a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber ContentValues initialValues = new ContentValues(); 28328a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber initialValues.put("album_id", album_id); 28338a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber try { 28348a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber ContentValues values = ensureFile(false, initialValues, "", ALBUM_THUMB_FOLDER); 28358a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber long rowId = db.insert("album_art", "_data", values); 28368a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (rowId > 0) { 28378a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber out = ContentUris.withAppendedId(ALBUMART_URI, rowId); 2838702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 28398a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } catch (IllegalStateException ex) { 28408a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber Log.e(TAG, "error creating album thumb file"); 28418a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 28428a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 28438a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber return out; 28448a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 28458a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 28468a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // Write out the album art to the output URI, recompresses the given Bitmap 28478a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // if necessary, otherwise writes the compressed data. 28488a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber private void writeAlbumArt( 28498a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber boolean need_to_recompress, Uri out, byte[] compressed, Bitmap bm) { 28508a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber boolean success = false; 28518a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber try { 28528a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber OutputStream outstream = getContext().getContentResolver().openOutputStream(out); 28538a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 28548a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (!need_to_recompress) { 28558a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // No need to recompress here, just write out the original 28568a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // compressed data here. 28578a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber outstream.write(compressed); 28588a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber success = true; 28598a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } else { 28608a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber success = bm.compress(Bitmap.CompressFormat.JPEG, 75, outstream); 2861702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 28628a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 28638a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber outstream.close(); 28648a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } catch (FileNotFoundException ex) { 28658a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber Log.e(TAG, "error creating file", ex); 2866702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } catch (IOException ex) { 28678a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber Log.e(TAG, "error creating file", ex); 28688a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 28698a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (!success) { 28708a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // the thumbnail was not written successfully, delete the entry that refers to it 28718a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber getContext().getContentResolver().delete(out, null, null); 2872702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 28738a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 28748a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 287571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen private ParcelFileDescriptor getThumb(SQLiteDatabase db, String path, long album_id, 287671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen Uri albumart_uri) { 287771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen ThumbData d = new ThumbData(); 287871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen d.db = db; 287971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen d.path = path; 288071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen d.album_id = album_id; 288171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen d.albumart_uri = albumart_uri; 288271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen return makeThumbInternal(d); 288371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 288471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen 288571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen private ParcelFileDescriptor makeThumbInternal(ThumbData d) { 28868a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber byte[] compressed = getCompressedAlbumArt(getContext(), d.path); 2887702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 28888a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (compressed == null) { 288971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen return null; 28908a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 28918a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 28928a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber Bitmap bm = null; 28938a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber boolean need_to_recompress = true; 28948a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 28958a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber try { 28968a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // get the size of the bitmap 28978a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber BitmapFactory.Options opts = new BitmapFactory.Options(); 28988a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.inJustDecodeBounds = true; 28998a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.inSampleSize = 1; 29008a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber BitmapFactory.decodeByteArray(compressed, 0, compressed.length, opts); 29018a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 29028a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // request a reasonably sized output image 29038a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // TODO: don't hardcode the size 29048a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber while (opts.outHeight > 320 || opts.outWidth > 320) { 29058a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.outHeight /= 2; 29068a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.outWidth /= 2; 29078a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.inSampleSize *= 2; 29088a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 29098a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 29108a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (opts.inSampleSize == 1) { 29118a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // The original album art was of proper size, we won't have to 29128a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // recompress the bitmap later. 29138a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber need_to_recompress = false; 29148a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } else { 29158a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber // get the image for real now 29168a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.inJustDecodeBounds = false; 29178a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber opts.inPreferredConfig = Bitmap.Config.RGB_565; 29188a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber bm = BitmapFactory.decodeByteArray(compressed, 0, compressed.length, opts); 29198a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 29208a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (bm != null && bm.getConfig() == null) { 2921a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen Bitmap nbm = bm.copy(Bitmap.Config.RGB_565, false); 2922a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen if (nbm != null && nbm != bm) { 2923a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen bm.recycle(); 2924a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen bm = nbm; 2925a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen } 29268a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 29278a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 29288a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } catch (Exception e) { 29298a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 29308a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 29318a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber if (need_to_recompress && bm == null) { 293271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen return null; 29338a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 29348a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber 293571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen if (d.albumart_uri == null) { 293671ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // this one doesn't need to be saved (probably a song with an unknown album), 293771ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen // so stick it in a memory file and return that 293871ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen try { 293971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen MemoryFile file = new MemoryFile("albumthumb", compressed.length); 294071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen file.writeBytes(compressed, 0, 0, compressed.length); 294171ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen file.deactivate(); 294271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen return file.getParcelFileDescriptor(); 294371ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } catch (IOException e) { 294471ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 294571ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } else { 2946a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen // This one needs to actually be saved on the sd card. 2947a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen // This is wrapped in a transaction because there are various things 2948a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen // that could go wrong while generating the thumbnail, and we only want 2949a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen // to update the database when all steps succeeded. 2950a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen d.db.beginTransaction(); 2951a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen try { 2952a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen Uri out = getAlbumArtOutputUri(d.db, d.album_id, d.albumart_uri); 2953a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen 2954a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen if (out != null) { 2955a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen writeAlbumArt(need_to_recompress, out, compressed, bm); 2956a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen getContext().getContentResolver().notifyChange(MEDIA_URI, null); 2957a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen ParcelFileDescriptor pfd = openFileHelper(out, "r"); 2958a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen d.db.setTransactionSuccessful(); 2959a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen return pfd; 2960a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen } 2961a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen } catch (FileNotFoundException ex) { 2962a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen // do nothing, just return null below 2963a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen } catch (UnsupportedOperationException ex) { 2964a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen // do nothing, just return null below 2965a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen } finally { 2966a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen d.db.endTransaction(); 2967a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen if (bm != null) { 2968a7953f20fc1f893712b07f9216d7b0e452eec779Marco Nelissen bm.recycle(); 296971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 297071ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen } 29718a4de789c3eafb17dd1eed82bc94fd9c2eb59e52Andreas Huber } 297271ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen return null; 2973702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 2974702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2975702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 2976702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Look up the artist or album entry for the given name, creating that entry 2977702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * if it does not already exists. 2978702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param db The database 2979702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param table The table to store the key/name pair in. 2980702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param keyField The name of the key-column 2981702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param nameField The name of the name-column 2982702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param rawName The name that the calling app was trying to insert into the database 298359948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen * @param cacheName The string that will be inserted in to the cache 298459948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen * @param path The full path to the file being inserted in to the audio table 298559948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen * @param albumHash A hash to distinguish between different albums of the same name 2986a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen * @param artist The name of the artist, if known 2987702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param cache The cache to add this entry to 2988702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param srcuri The Uri that prompted the call to this method, used for determining whether this is 2989702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * the internal or external database 2990702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @return The row ID for this artist/album, or -1 if the provided name was invalid 2991702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 2992702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private long getKeyIdForName(SQLiteDatabase db, String table, String keyField, String nameField, 299359948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen String rawName, String cacheName, String path, int albumHash, 2994a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen String artist, HashMap<String, Long> cache, Uri srcuri) { 2995702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project long rowId; 2996702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 2997702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rawName == null || rawName.length() == 0) { 2998702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return -1; 2999702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3000702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String k = MediaStore.Audio.keyFor(rawName); 3001702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3002702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (k == null) { 3003702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return -1; 3004702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3005702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 300659948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen boolean isAlbum = table.equals("albums"); 3007e31cfb1a2c21e7ac7a646d40afbb48f49fab6907Marco Nelissen boolean isUnknown = MediaStore.UNKNOWN_STRING.equals(rawName); 300859948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen 300959948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // To distinguish same-named albums, we append a hash of the path. 301059948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // Ideally we would also take things like CDDB ID in to account, so 301159948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // we can group files from the same album that aren't in the same 301259948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // folder, but this is a quick and easy start that works immediately 301359948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // without requiring support from the mp3, mp4 and Ogg meta data 301459948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen // readers, as long as the albums are in different folders. 3015a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen if (isAlbum) { 301659948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen k = k + albumHash; 3017a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen if (isUnknown) { 3018a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen k = k + artist; 3019a4d451b5aecc8b2aed0bc6ea341e097697aeeeb2Marco Nelissen } 302059948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen } 302159948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen 3022702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String [] selargs = { k }; 3023702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Cursor c = db.query(table, null, keyField + "=?", selargs, null, null, null); 3024702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3025702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 3026702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project switch (c.getCount()) { 3027702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case 0: { 3028702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // insert new entry into table 3029702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues otherValues = new ContentValues(); 3030702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project otherValues.put(keyField, k); 3031702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project otherValues.put(nameField, rawName); 3032702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = db.insert(table, "duration", otherValues); 303359948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen if (path != null && isAlbum && ! isUnknown) { 3034702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // We just inserted a new album. Now create an album art thumbnail for it. 3035a9c4e330dacb37cfffa9c00f7da83cafde4accefMarco Nelissen makeThumbAsync(db, path, rowId); 3036702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3037702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (rowId > 0) { 3038702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String volume = srcuri.toString().substring(16, 24); // extract internal/external 3039702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Uri uri = Uri.parse("content://media/" + volume + "/audio/" + table + "/" + rowId); 3040702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 3041702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3042702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3043702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3044702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project case 1: { 3045702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Use the existing entry 3046702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project c.moveToFirst(); 3047702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = c.getLong(0); 3048702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3049702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Determine whether the current rawName is better than what's 3050702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // currently stored in the table, and update the table if it is. 3051702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String currentFancyName = c.getString(2); 3052702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String bestName = makeBestName(rawName, currentFancyName); 3053702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!bestName.equals(currentFancyName)) { 3054702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // update the table with the new name 3055702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ContentValues newValues = new ContentValues(); 3056702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project newValues.put(nameField, bestName); 3057702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db.update(table, newValues, "rowid="+Integer.toString((int)rowId), null); 3058702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String volume = srcuri.toString().substring(16, 24); // extract internal/external 3059702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Uri uri = Uri.parse("content://media/" + volume + "/audio/" + table + "/" + rowId); 3060702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 3061702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3062702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3063702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3064702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project default: 3065702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // corrupt database 3066702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Log.e(TAG, "Multiple entries in table " + table + " for key " + k); 3067702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project rowId = -1; 3068702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project break; 3069702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3070702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 3071702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (c != null) c.close(); 3072702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3073702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 307459948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen if (cache != null && ! isUnknown) { 307559948d12c73d9132fbf3930eb93897baab1a94daMarco Nelissen cache.put(cacheName, rowId); 3076702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3077702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return rowId; 3078702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3079702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3080702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 3081702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Returns the best string to use for display, given two names. 3082702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Note that this function does not necessarily return either one 3083702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * of the provided names; it may decide to return a better alternative 3084702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * (for example, specifying the inputs "Police" and "Police, The" will 3085702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * return "The Police") 3086702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 3087702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * The basic assumptions are: 3088702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * - longer is better ("The police" is better than "Police") 3089702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * - prefix is better ("The Police" is better than "Police, The") 3090702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * - accents are better ("Motörhead" is better than "Motorhead") 3091702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 3092702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param one The first of the two names to consider 3093702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param two The last of the two names to consider 3094702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @return The actual name to use 3095702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 3096702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String makeBestName(String one, String two) { 3097702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String name; 3098702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3099702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Longer names are usually better. 3100702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (one.length() > two.length()) { 3101702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project name = one; 3102702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 3103702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Names with accents are usually better, and conveniently sort later 3104702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (one.toLowerCase().compareTo(two.toLowerCase()) > 0) { 3105702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project name = one; 3106702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 3107702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project name = two; 3108702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3109702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3110702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3111702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Prefixes are better than postfixes. 3112702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (name.endsWith(", the") || name.endsWith(",the") || 3113702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project name.endsWith(", an") || name.endsWith(",an") || 3114702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project name.endsWith(", a") || name.endsWith(",a")) { 3115702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String fix = name.substring(1 + name.lastIndexOf(',')); 3116702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project name = fix.trim() + " " + name.substring(0, name.lastIndexOf(',')); 3117702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3118702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3119702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // TODO: word-capitalize the resulting name 3120702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return name; 3121702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3122702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3123702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3124702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 3125702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Looks up the database based on the given URI. 3126702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 3127702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param uri The requested URI 3128702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @returns the database for the given URI 3129702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 3130702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private DatabaseHelper getDatabaseForUri(Uri uri) { 3131702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized (mDatabases) { 3132702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (uri.getPathSegments().size() > 1) { 3133702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return mDatabases.get(uri.getPathSegments().get(0)); 3134702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3135702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3136702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return null; 3137702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3138702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3139702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 3140702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Attach the database for a volume (internal or external). 3141702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Does nothing if the volume is already attached, otherwise 3142702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * checks the volume ID and sets up the corresponding database. 3143702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 3144702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param volume to attach, either {@link #INTERNAL_VOLUME} or {@link #EXTERNAL_VOLUME}. 3145702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @return the content URI of the attached volume. 3146702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 3147702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private Uri attachVolume(String volume) { 3148702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (Process.supportsProcesses() && Binder.getCallingPid() != Process.myPid()) { 3149702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new SecurityException( 3150702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Opening and closing databases not allowed."); 3151702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3152702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3153702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized (mDatabases) { 3154702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (mDatabases.get(volume) != null) { // Already attached 3155702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Uri.parse("content://media/" + volume); 3156702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3157702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3158702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DatabaseHelper db; 3159702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (INTERNAL_VOLUME.equals(volume)) { 3160702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db = new DatabaseHelper(getContext(), INTERNAL_DATABASE_NAME, true); 3161702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else if (EXTERNAL_VOLUME.equals(volume)) { 3162702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String path = Environment.getExternalStorageDirectory().getPath(); 3163702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project int volumeID = FileUtils.getFatVolumeId(path); 3164702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (LOCAL_LOGV) Log.v(TAG, path + " volume ID: " + volumeID); 3165702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3166702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // generate database name based on volume ID 3167702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String dbName = "external-" + Integer.toHexString(volumeID) + ".db"; 3168702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project db = new DatabaseHelper(getContext(), dbName, false); 31690027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen mVolumeId = volumeID; 3170702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else { 3171702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalArgumentException("There is no volume named " + volume); 3172702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3173702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3174702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mDatabases.put(volume, db); 3175702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3176702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (!db.mInternal) { 3177702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // clean up stray album art files: delete every file not in the database 3178702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File[] files = new File( 3179702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Environment.getExternalStorageDirectory(), 3180702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project ALBUM_THUMB_FOLDER).listFiles(); 3181702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project HashSet<String> fileSet = new HashSet(); 3182702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project for (int i = 0; files != null && i < files.length; i++) { 3183702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project fileSet.add(files[i].getPath()); 3184702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3185702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3186702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Cursor cursor = query(MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI, 3187702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project new String[] { MediaStore.Audio.Albums.ALBUM_ART }, null, null, null); 3188702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 3189702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project while (cursor != null && cursor.moveToNext()) { 3190702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project fileSet.remove(cursor.getString(0)); 3191702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3192702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } finally { 3193702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (cursor != null) cursor.close(); 3194702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3195702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3196702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Iterator<String> iterator = fileSet.iterator(); 3197702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project while (iterator.hasNext()) { 3198702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String filename = iterator.next(); 3199702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (LOCAL_LOGV) Log.v(TAG, "deleting obsolete album art " + filename); 3200702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project new File(filename).delete(); 3201702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3202702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3203702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3204702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3205702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (LOCAL_LOGV) Log.v(TAG, "Attached volume: " + volume); 3206702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project return Uri.parse("content://media/" + volume); 3207702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3208702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3209702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project /** 3210702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Detach the database for a volume (must be external). 3211702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * Does nothing if the volume is already detached, otherwise 3212702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * closes the database and sends a notification to listeners. 3213702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * 3214702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project * @param uri The content URI of the volume, as returned by {@link #attachVolume} 3215702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project */ 3216702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private void detachVolume(Uri uri) { 3217702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (Process.supportsProcesses() && Binder.getCallingPid() != Process.myPid()) { 3218702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new SecurityException( 3219702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Opening and closing databases not allowed."); 3220702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3221702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3222702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project String volume = uri.getPathSegments().get(0); 3223702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (INTERNAL_VOLUME.equals(volume)) { 3224702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new UnsupportedOperationException( 3225702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "Deleting the internal volume is not allowed"); 3226702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } else if (!EXTERNAL_VOLUME.equals(volume)) { 3227702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project throw new IllegalArgumentException( 3228702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "There is no volume named " + volume); 3229702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3230702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3231702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project synchronized (mDatabases) { 3232702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project DatabaseHelper database = mDatabases.get(volume); 3233702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (database == null) return; 3234702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3235702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project try { 3236702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // touch the database file to show it is most recently used 3237702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project File file = new File(database.getReadableDatabase().getPath()); 3238702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project file.setLastModified(System.currentTimeMillis()); 3239702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } catch (SQLException e) { 3240702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project Log.e(TAG, "Can't touch database file", e); 3241702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3242702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3243702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project mDatabases.remove(volume); 3244702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project database.close(); 3245702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3246702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3247702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project getContext().getContentResolver().notifyChange(uri, null); 3248702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project if (LOCAL_LOGV) Log.v(TAG, "Detached volume: " + volume); 3249702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3250702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3251702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static String TAG = "MediaProvider"; 3252ae62a1d602e7ed2e0e30e271bddbb27aa71469f6Christian Mehlmauer private static final boolean LOCAL_LOGV = false; 32539ea338b3f2720a16a334990bf2bb6afc5011b60eMike Lockwood private static final int DATABASE_VERSION = 93; 3254702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final String INTERNAL_DATABASE_NAME = "internal.db"; 3255702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3256702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // maximum number of cached external databases to keep 3257702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int MAX_EXTERNAL_DATABASES = 3; 3258702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3259702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // Delete databases that have not been used in two months 3260702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // 60 days in milliseconds (1000 * 60 * 60 * 24 * 60) 3261702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final long OBSOLETE_DATABASE_DB = 5184000000L; 3262702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3263702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private HashMap<String, DatabaseHelper> mDatabases; 3264702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3265702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private Handler mThumbHandler; 3266702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3267702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // name of the volume currently being scanned by the media scanner (or null) 3268702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private String mMediaScannerVolume; 3269702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 32700027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen // current FAT volume ID 32710027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen private int mVolumeId; 32720027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen 3273702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project static final String INTERNAL_VOLUME = "internal"; 3274702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project static final String EXTERNAL_VOLUME = "external"; 3275268435e85a053ac447baed4a401ca12b3ea7e6e1Marco Nelissen static final String ALBUM_THUMB_FOLDER = "Android/data/com.android.providers.media/albumthumbs"; 3276702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3277702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project // path for writing contents of in memory temp database 3278702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private String mTempDatabasePath; 3279702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 32801717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood // WARNING: the values of IMAGES_MEDIA, AUDIO_MEDIA, and VIDEO_MEDIA and AUDIO_PLAYLISTS 32811717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood // are stored in the "objects" table, so do not renumber them unless you also add 32821717955cb3b68424ee7dbf7c644000cf82788253Mike Lockwood // a corresponding database upgrade step for it. 3283702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int IMAGES_MEDIA = 1; 3284702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int IMAGES_MEDIA_ID = 2; 3285702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int IMAGES_THUMBNAILS = 3; 3286702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int IMAGES_THUMBNAILS_ID = 4; 3287702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3288702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_MEDIA = 100; 3289702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_MEDIA_ID = 101; 3290702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_MEDIA_ID_GENRES = 102; 3291702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_MEDIA_ID_GENRES_ID = 103; 3292702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_MEDIA_ID_PLAYLISTS = 104; 3293702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_MEDIA_ID_PLAYLISTS_ID = 105; 3294702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_GENRES = 106; 3295702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_GENRES_ID = 107; 3296702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_GENRES_ID_MEMBERS = 108; 3297702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_GENRES_ID_MEMBERS_ID = 109; 3298702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_PLAYLISTS = 110; 3299702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_PLAYLISTS_ID = 111; 3300702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_PLAYLISTS_ID_MEMBERS = 112; 3301702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_PLAYLISTS_ID_MEMBERS_ID = 113; 3302702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ARTISTS = 114; 3303702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ARTISTS_ID = 115; 3304702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ALBUMS = 116; 3305702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ALBUMS_ID = 117; 3306702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ARTISTS_ID_ALBUMS = 118; 3307702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ALBUMART = 119; 3308702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int AUDIO_ALBUMART_ID = 120; 330971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen private static final int AUDIO_ALBUMART_FILE_ID = 121; 3310702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3311702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int VIDEO_MEDIA = 200; 3312702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int VIDEO_MEDIA_ID = 201; 3313b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private static final int VIDEO_THUMBNAILS = 202; 3314b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private static final int VIDEO_THUMBNAILS_ID = 203; 3315702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3316702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int VOLUMES = 300; 3317702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int VOLUMES_ID = 301; 3318702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3319a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen private static final int AUDIO_SEARCH_LEGACY = 400; 3320a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen private static final int AUDIO_SEARCH_BASIC = 401; 3321a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen private static final int AUDIO_SEARCH_FANCY = 402; 3322702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3323702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final int MEDIA_SCANNER = 500; 3324702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 33250027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen private static final int FS_ID = 600; 33260027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen 3327b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood private static final int MTP_OBJECTS = 700; 3328b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood private static final int MTP_OBJECTS_ID = 701; 3329b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 3330702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final UriMatcher URI_MATCHER = 3331702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project new UriMatcher(UriMatcher.NO_MATCH); 3332702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3333b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private static final String[] ID_PROJECTION = new String[] { 3334b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen MediaStore.MediaColumns._ID 3335b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen }; 3336b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 3337702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final String[] MIME_TYPE_PROJECTION = new String[] { 3338702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.MediaColumns._ID, // 0 3339702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project MediaStore.MediaColumns.MIME_TYPE, // 1 3340702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project }; 3341702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3342b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen private static final String[] READY_FLAG_PROJECTION = new String[] { 3343b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen MediaStore.MediaColumns._ID, 3344b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen MediaStore.MediaColumns.DATA, 3345b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen Images.Media.MINI_THUMB_MAGIC 3346b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen }; 3347b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen 3348702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project private static final String[] EXTERNAL_DATABASE_TABLES = new String[] { 3349702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "images", 3350702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "thumbnails", 3351702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_meta", 3352702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "artists", 3353702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "albums", 3354702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_genres", 3355702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_genres_map", 3356702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_playlists", 3357702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "audio_playlists_map", 3358702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project "video", 3359702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project }; 3360702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3361702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project static 3362702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project { 3363702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/images/media", IMAGES_MEDIA); 3364702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/images/media/#", IMAGES_MEDIA_ID); 3365702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/images/thumbnails", IMAGES_THUMBNAILS); 3366702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/images/thumbnails/#", IMAGES_THUMBNAILS_ID); 3367702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3368702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/media", AUDIO_MEDIA); 3369702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/media/#", AUDIO_MEDIA_ID); 3370702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/media/#/genres", AUDIO_MEDIA_ID_GENRES); 3371702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/media/#/genres/#", AUDIO_MEDIA_ID_GENRES_ID); 3372702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/media/#/playlists", AUDIO_MEDIA_ID_PLAYLISTS); 3373702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/media/#/playlists/#", AUDIO_MEDIA_ID_PLAYLISTS_ID); 3374702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/genres", AUDIO_GENRES); 3375702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/genres/#", AUDIO_GENRES_ID); 3376702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/genres/#/members", AUDIO_GENRES_ID_MEMBERS); 3377702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/genres/#/members/#", AUDIO_GENRES_ID_MEMBERS_ID); 3378702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/playlists", AUDIO_PLAYLISTS); 3379702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/playlists/#", AUDIO_PLAYLISTS_ID); 3380702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/playlists/#/members", AUDIO_PLAYLISTS_ID_MEMBERS); 3381702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/playlists/#/members/#", AUDIO_PLAYLISTS_ID_MEMBERS_ID); 3382702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/artists", AUDIO_ARTISTS); 3383702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/artists/#", AUDIO_ARTISTS_ID); 3384702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/artists/#/albums", AUDIO_ARTISTS_ID_ALBUMS); 3385702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/albums", AUDIO_ALBUMS); 3386702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/albums/#", AUDIO_ALBUMS_ID); 3387702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/albumart", AUDIO_ALBUMART); 3388702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/albumart/#", AUDIO_ALBUMART_ID); 338971ece60b1465f2289851fe3fc5fa7c867ba5804dMarco Nelissen URI_MATCHER.addURI("media", "*/audio/media/#/albumart", AUDIO_ALBUMART_FILE_ID); 3390702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3391702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/video/media", VIDEO_MEDIA); 3392702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/video/media/#", VIDEO_MEDIA_ID); 3393b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen URI_MATCHER.addURI("media", "*/video/thumbnails", VIDEO_THUMBNAILS); 3394b386112a8c5e5bd2d3d77e5398bea26b2172dffcRay Chen URI_MATCHER.addURI("media", "*/video/thumbnails/#", VIDEO_THUMBNAILS_ID); 3395702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3396702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/media_scanner", MEDIA_SCANNER); 3397702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 33980027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen URI_MATCHER.addURI("media", "*/fs_id", FS_ID); 33990027019c6190f6bfa6935904107f23c8e75b1ffdMarco Nelissen 3400702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*", VOLUMES_ID); 3401702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", null, VOLUMES); 3402702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project 3403b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood // Used by MTP implementation 3404b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood URI_MATCHER.addURI("media", "*/object", MTP_OBJECTS); 3405b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood URI_MATCHER.addURI("media", "*/object/#", MTP_OBJECTS_ID); 3406b78ad0d07a40f0d72dbe6c9ff365ddcfef316eb0Mike Lockwood 3407a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen /** 3408a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen * @deprecated use the 'basic' or 'fancy' search Uris instead 3409a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen */ 3410702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/" + SearchManager.SUGGEST_URI_PATH_QUERY, 3411a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen AUDIO_SEARCH_LEGACY); 3412702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project URI_MATCHER.addURI("media", "*/audio/" + SearchManager.SUGGEST_URI_PATH_QUERY + "/*", 3413a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen AUDIO_SEARCH_LEGACY); 3414a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen 3415a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // used for search suggestions 3416a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen URI_MATCHER.addURI("media", "*/audio/search/" + SearchManager.SUGGEST_URI_PATH_QUERY, 3417a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen AUDIO_SEARCH_BASIC); 3418a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen URI_MATCHER.addURI("media", "*/audio/search/" + SearchManager.SUGGEST_URI_PATH_QUERY + 3419a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen "/*", AUDIO_SEARCH_BASIC); 3420a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen 3421a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen // used by the music app's search activity 3422a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen URI_MATCHER.addURI("media", "*/audio/search/fancy", AUDIO_SEARCH_FANCY); 3423a65c5443d17d497703272b7ae2f0aa5b165bff3fMarco Nelissen URI_MATCHER.addURI("media", "*/audio/search/fancy/*", AUDIO_SEARCH_FANCY); 3424702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project } 3425702152725052b7b3903ed647cf53f04724886a1bThe Android Open Source Project} 3426