MediaScanner.java revision f3fd18d1b4cb44bb31a5b4fba26136f6f4fc37ad
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License. 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.media; 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 19bfcb22a207499c7ecd4aef9bea2ac778d8be8fc8Marco Nelissenimport org.xml.sax.Attributes; 20bfcb22a207499c7ecd4aef9bea2ac778d8be8fc8Marco Nelissenimport org.xml.sax.ContentHandler; 21bfcb22a207499c7ecd4aef9bea2ac778d8be8fc8Marco Nelissenimport org.xml.sax.SAXException; 22bfcb22a207499c7ecd4aef9bea2ac778d8be8fc8Marco Nelissen 23bfcb22a207499c7ecd4aef9bea2ac778d8be8fc8Marco Nelissenimport android.content.ContentUris; 249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ContentValues; 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context; 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.IContentProvider; 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.database.Cursor; 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.database.SQLException; 295d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wangimport android.drm.DrmManagerClient; 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.BitmapFactory; 310cd0136d440cf6ad9d5fab430269116786e671ecMike Lockwoodimport android.mtp.MtpConstants; 329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.Uri; 33250528e5b2362cb7b6749afb331acd8226f67744Mike Lockwoodimport android.os.Environment; 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.RemoteException; 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemProperties; 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.MediaStore; 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.MediaStore.Audio; 380b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissenimport android.provider.MediaStore.Audio.Playlists; 39c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwoodimport android.provider.MediaStore.Files; 400b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissenimport android.provider.MediaStore.Files.FileColumns; 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.MediaStore.Images; 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.MediaStore.Video; 430b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissenimport android.provider.Settings; 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.sax.Element; 459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.sax.ElementListener; 469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.sax.RootElement; 4734385d352da19805ae948215e2edbeedd16b7941Elliott Hughesimport android.system.ErrnoException; 4834385d352da19805ae948215e2edbeedd16b7941Elliott Hughesimport android.system.Os; 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.TextUtils; 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log; 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Xml; 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 53bfcb22a207499c7ecd4aef9bea2ac778d8be8fc8Marco Nelissenimport java.io.BufferedReader; 54bfcb22a207499c7ecd4aef9bea2ac778d8be8fc8Marco Nelissenimport java.io.File; 55bfcb22a207499c7ecd4aef9bea2ac778d8be8fc8Marco Nelissenimport java.io.FileDescriptor; 56bfcb22a207499c7ecd4aef9bea2ac778d8be8fc8Marco Nelissenimport java.io.FileInputStream; 57bfcb22a207499c7ecd4aef9bea2ac778d8be8fc8Marco Nelissenimport java.io.IOException; 58bfcb22a207499c7ecd4aef9bea2ac778d8be8fc8Marco Nelissenimport java.io.InputStreamReader; 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList; 609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.HashSet; 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Iterator; 62ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissenimport java.util.Locale; 639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 6577f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * Internal service helper that no-one should use directly. 6620b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync * 6777f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * The way the scan currently works is: 6877f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * - The Java MediaScannerService creates a MediaScanner (this class), and calls 6977f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * MediaScanner.scanDirectories on it. 7077f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * - scanDirectories() calls the native processDirectory() for each of the specified directories. 7177f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * - the processDirectory() JNI method wraps the provided mediascanner client in a native 7277f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * 'MyMediaScannerClient' class, then calls processDirectory() on the native MediaScanner 7377f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * object (which got created when the Java MediaScanner was created). 747ae82ce1fd54103bb87b8a0593a4228c94b1d6f9James Dong * - native MediaScanner.processDirectory() calls 7577f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * doProcessDirectory(), which recurses over the folder, and calls 7677f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * native MyMediaScannerClient.scanFile() for every file whose extension matches. 7777f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * - native MyMediaScannerClient.scanFile() calls back on Java MediaScannerClient.scanFile, 7877f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * which calls doScanFile, which after some setup calls back down to native code, calling 7977f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * MediaScanner.processFile(). 8077f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * - MediaScanner.processFile() calls one of several methods, depending on the type of the 8177f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * file: parseMP3, parseMP4, parseMidi, parseOgg or parseWMA. 8277f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * - each of these methods gets metadata key/value pairs from the file, and repeatedly 8377f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * calls native MyMediaScannerClient.handleStringTag, which calls back up to its Java 8477f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * counterparts in this file. 8577f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * - Java handleStringTag() gathers the key/value pairs that it's interested in. 8677f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * - once processFile returns and we're back in Java code in doScanFile(), it calls 8777f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * Java MyMediaScannerClient.endFile(), which takes all the data that's been 8877f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * gathered and inserts an entry in to the database. 8977f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * 9077f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * In summary: 9177f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * Java MediaScannerService calls 9277f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * Java MediaScanner scanDirectories, which calls 9377f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * Java MediaScanner processDirectory (native method), which calls 9477f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * native MediaScanner processDirectory, which calls 9577f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * native MyMediaScannerClient scanFile, which calls 9677f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * Java MyMediaScannerClient scanFile, which calls 9777f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * Java MediaScannerClient doScanFile, which calls 9877f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * Java MediaScanner processFile (native method), which calls 9977f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * native MediaScanner processFile, which calls 10077f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * native parseMP3, parseMP4, parseMidi, parseOgg or parseWMA, which calls 10177f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * native MyMediaScanner handleStringTag, which calls 10277f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * Java MyMediaScanner handleStringTag. 10377f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * Once MediaScanner processFile returns, an entry is inserted in to the database. 1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 105af16d0b30e89f31b7617424c8706553ff571d08dMike Lockwood * The MediaScanner class is not thread-safe, so it should only be used in a single threaded manner. 106af16d0b30e89f31b7617424c8706553ff571d08dMike Lockwood * 1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@hide} 1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class MediaScanner 11020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync{ 1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static { 1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project System.loadLibrary("media_jni"); 1134935d05eaa306cef88cf0ab13eca386f270409ecMarco Nelissen native_init(); 1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final static String TAG = "MediaScanner"; 1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 118d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood private static final String[] FILES_PRESCAN_PROJECTION = new String[] { 119c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood Files.FileColumns._ID, // 0 120c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood Files.FileColumns.DATA, // 1 121d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood Files.FileColumns.FORMAT, // 2 122d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood Files.FileColumns.DATE_MODIFIED, // 3 1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 12420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 1256458935331ccfacb4cccc50d6b893947febae687Mike Lockwood private static final String[] ID_PROJECTION = new String[] { 1266458935331ccfacb4cccc50d6b893947febae687Mike Lockwood Files.FileColumns._ID, 1276458935331ccfacb4cccc50d6b893947febae687Mike Lockwood }; 1286458935331ccfacb4cccc50d6b893947febae687Mike Lockwood 129d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood private static final int FILES_PRESCAN_ID_COLUMN_INDEX = 0; 130d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood private static final int FILES_PRESCAN_PATH_COLUMN_INDEX = 1; 131d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood private static final int FILES_PRESCAN_FORMAT_COLUMN_INDEX = 2; 132d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood private static final int FILES_PRESCAN_DATE_MODIFIED_COLUMN_INDEX = 3; 133d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood 1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String[] PLAYLIST_MEMBERS_PROJECTION = new String[] { 1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Audio.Playlists.Members.PLAYLIST_ID, // 0 1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int ID_PLAYLISTS_COLUMN_INDEX = 0; 1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int PATH_PLAYLISTS_COLUMN_INDEX = 1; 1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int DATE_MODIFIED_PLAYLISTS_COLUMN_INDEX = 2; 1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String RINGTONES_DIR = "/ringtones/"; 1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String NOTIFICATIONS_DIR = "/notifications/"; 1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String ALARMS_DIR = "/alarms/"; 1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String MUSIC_DIR = "/music/"; 1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String PODCAST_DIR = "/podcasts/"; 14720b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String[] ID3_GENRES = { 1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // ID3v1 Genres 1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Blues", 1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Classic Rock", 1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Country", 1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Dance", 1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Disco", 1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Funk", 1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Grunge", 1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Hip-Hop", 1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Jazz", 1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Metal", 1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "New Age", 1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Oldies", 1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Other", 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Pop", 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "R&B", 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Rap", 1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Reggae", 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Rock", 1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Techno", 1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Industrial", 1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Alternative", 1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Ska", 1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Death Metal", 1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Pranks", 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Soundtrack", 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Euro-Techno", 1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Ambient", 1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Trip-Hop", 1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Vocal", 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Jazz+Funk", 1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Fusion", 1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Trance", 1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Classical", 1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Instrumental", 1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Acid", 1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "House", 1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Game", 1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Sound Clip", 1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Gospel", 1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Noise", 1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "AlternRock", 1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Bass", 1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Soul", 1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Punk", 1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Space", 1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Meditative", 1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Instrumental Pop", 1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Instrumental Rock", 1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Ethnic", 1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Gothic", 2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Darkwave", 2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Techno-Industrial", 2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Electronic", 2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Pop-Folk", 2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Eurodance", 2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Dream", 2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Southern Rock", 2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Comedy", 2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Cult", 2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Gangsta", 2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Top 40", 2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Christian Rap", 2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Pop/Funk", 2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Jungle", 2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Native American", 2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Cabaret", 2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "New Wave", 2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Psychadelic", 2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Rave", 2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Showtunes", 2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Trailer", 2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Lo-Fi", 2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Tribal", 2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Acid Punk", 2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Acid Jazz", 2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Polka", 2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Retro", 2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Musical", 2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Rock & Roll", 2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Hard Rock", 2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // The following genres are Winamp extensions 2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Folk", 2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Folk-Rock", 2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "National Folk", 2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Swing", 2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Fast Fusion", 2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Bebob", 2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Latin", 2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Revival", 2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Celtic", 2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Bluegrass", 2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Avantgarde", 2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Gothic Rock", 2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Progressive Rock", 2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Psychedelic Rock", 2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Symphonic Rock", 2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Slow Rock", 2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Big Band", 2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Chorus", 2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Easy Listening", 2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Acoustic", 2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Humour", 2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Speech", 2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Chanson", 2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Opera", 2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Chamber Music", 2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Sonata", 2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Symphony", 2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Booty Bass", 2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Primus", 2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Porn Groove", 2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Satire", 2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Slow Jam", 2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Club", 2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Tango", 2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Samba", 2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Folklore", 2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Ballad", 2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Power Ballad", 2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Rhythmic Soul", 2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Freestyle", 2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Duet", 2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Punk Rock", 2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Drum Solo", 2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "A capella", 2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Euro-House", 276cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen "Dance Hall", 277cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen // The following ones seem to be fairly widely supported as well 278cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen "Goa", 279cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen "Drum & Bass", 280cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen "Club-House", 281cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen "Hardcore", 282cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen "Terror", 283cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen "Indie", 284cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen "Britpop", 285c3ea477e2111f199d10341b121791cb2ec91eca3Johan Redestig null, 286cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen "Polsk Punk", 287cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen "Beat", 288cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen "Christian Gangsta", 289cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen "Heavy Metal", 290cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen "Black Metal", 291cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen "Crossover", 292cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen "Contemporary Christian", 293cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen "Christian Rock", 294cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen "Merengue", 295cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen "Salsa", 296cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen "Thrash Metal", 297cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen "Anime", 298cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen "JPop", 299cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen "Synthpop", 300cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen // 148 and up don't seem to have been defined yet. 3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 303075e9a19ce645752f8282bc19c91b25978a7dc52Ashok Bhat private long mNativeContext; 3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Context mContext; 30535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn private String mPackageName; 3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private IContentProvider mMediaProvider; 3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Uri mAudioUri; 3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Uri mVideoUri; 3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Uri mImagesUri; 3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Uri mThumbsUri; 3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Uri mPlaylistsUri; 312c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood private Uri mFilesUri; 3138ad76fa7a644c10abb7b95398fdb8a84bd723619Marco Nelissen private Uri mFilesUriNoNotify; 31443b076bb75e86fbb34cbe36aa0298c7a647121ffMike Lockwood private boolean mProcessPlaylists, mProcessGenres; 315d815f79766984fce499e147ecbacc01914683f74Mike Lockwood private int mMtpObjectHandle; 3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 317250528e5b2362cb7b6749afb331acd8226f67744Mike Lockwood private final String mExternalStoragePath; 318c861411d4bae0912054ff54c3efee90ae2db6db9Marco Nelissen private final boolean mExternalIsEmulated; 319250528e5b2362cb7b6749afb331acd8226f67744Mike Lockwood 320d6b3e0cc36cbe28c8d194b63227df37c76af7efaMarco Nelissen /** whether to use bulk inserts or individual inserts for each item */ 321d6b3e0cc36cbe28c8d194b63227df37c76af7efaMarco Nelissen private static final boolean ENABLE_BULK_INSERTS = true; 3223410b4656505673c72da558dcfec94d7b135e760Mike Lockwood 3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // used when scanning the image database so we know whether we have to prune 3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // old thumbnail files 3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mOriginalCount; 326bcbddd9342ee5ef48617ce7dcca6c505df3fcf08Marco Nelissen /** Whether the database had any entries in it before the scan started */ 327bcbddd9342ee5ef48617ce7dcca6c505df3fcf08Marco Nelissen private boolean mWasEmptyPriorToScan = false; 3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** Whether the scanner has set a default sound for the ringer ringtone. */ 3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mDefaultRingtoneSet; 3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** Whether the scanner has set a default sound for the notification ringtone. */ 3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mDefaultNotificationSet; 3323156bb00dd3ab3d6ec732bb6a64a2e84d08c34f0Patrick Scott /** Whether the scanner has set a default sound for the alarm ringtone. */ 3333156bb00dd3ab3d6ec732bb6a64a2e84d08c34f0Patrick Scott private boolean mDefaultAlarmSet; 3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** The filename for the default sound for the ringer ringtone. */ 3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String mDefaultRingtoneFilename; 3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** The filename for the default sound for the notification ringtone. */ 3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String mDefaultNotificationFilename; 3383156bb00dd3ab3d6ec732bb6a64a2e84d08c34f0Patrick Scott /** The filename for the default sound for the alarm ringtone. */ 3393156bb00dd3ab3d6ec732bb6a64a2e84d08c34f0Patrick Scott private String mDefaultAlarmAlertFilename; 3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The prefix for system properties that define the default sound for 3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * ringtones. Concatenate the name of the setting from Settings 3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * to get the full system property. 3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String DEFAULT_RINGTONE_PROPERTY_PREFIX = "ro.config."; 34620b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // set to true if file path comparisons should be case insensitive. 3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // this should be set when scanning files on a case insensitive file system. 3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mCaseInsensitivePaths; 35020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 35130c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten private final BitmapFactory.Options mBitmapOptions = new BitmapFactory.Options(); 3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 35358ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen private static class FileEntry { 3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long mRowId; 3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String mPath; 3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long mLastModified; 357d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood int mFormat; 3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean mLastModifiedChanged; 35920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 36058ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen FileEntry(long rowId, String path, long lastModified, int format) { 3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mRowId = rowId; 3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPath = path; 3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLastModified = lastModified; 364d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood mFormat = format; 3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLastModifiedChanged = false; 3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String toString() { 3703e5e8055942ee8179675b8ed11d40ca12dbe42e6Marco Nelissen return mPath + " mRowId: " + mRowId; 3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 37320b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 3740b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen private static class PlaylistEntry { 3750b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen String path; 3760b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen long bestmatchid; 3770b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen int bestmatchlevel; 3780b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen } 3790b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen 3800b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen private ArrayList<PlaylistEntry> mPlaylistEntries = new ArrayList<PlaylistEntry>(); 3810b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen 3828e2ed8d512ade2ea481b3a292556782b17a74674Dongwon Kang private MediaInserter mMediaInserter; 383bd682b040833fce9e212c00c395b32bec7050f87Mike Lockwood 38458ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen private ArrayList<FileEntry> mPlayLists; 3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3865d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang private DrmManagerClient mDrmManagerClient = null; 3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public MediaScanner(Context c) { 3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project native_setup(); 3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext = c; 39135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn mPackageName = c.getPackageName(); 3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mBitmapOptions.inSampleSize = 1; 3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mBitmapOptions.inJustDecodeBounds = true; 39420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setDefaultRingtoneFileNames(); 396250528e5b2362cb7b6749afb331acd8226f67744Mike Lockwood 397250528e5b2362cb7b6749afb331acd8226f67744Mike Lockwood mExternalStoragePath = Environment.getExternalStorageDirectory().getAbsolutePath(); 398c861411d4bae0912054ff54c3efee90ae2db6db9Marco Nelissen mExternalIsEmulated = Environment.isExternalStorageEmulated(); 399ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen //mClient.testGenreNameConverter(); 4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void setDefaultRingtoneFileNames() { 4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDefaultRingtoneFilename = SystemProperties.get(DEFAULT_RINGTONE_PROPERTY_PREFIX 4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + Settings.System.RINGTONE); 4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDefaultNotificationFilename = SystemProperties.get(DEFAULT_RINGTONE_PROPERTY_PREFIX 4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + Settings.System.NOTIFICATION_SOUND); 4073156bb00dd3ab3d6ec732bb6a64a2e84d08c34f0Patrick Scott mDefaultAlarmAlertFilename = SystemProperties.get(DEFAULT_RINGTONE_PROPERTY_PREFIX 4083156bb00dd3ab3d6ec732bb6a64a2e84d08c34f0Patrick Scott + Settings.System.ALARM_ALERT); 4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 41020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 41130c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten private final MyMediaScannerClient mClient = new MyMediaScannerClient(); 41220b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 413e4eb4d9de37a8e9ed6f43a5f7deccf88f28bfc8bMarco Nelissen private boolean isDrmEnabled() { 4141f89c4f9f8df5d7125221250993ba1e853ed9fedGloria Wang String prop = SystemProperties.get("drm.service.enabled"); 415e4eb4d9de37a8e9ed6f43a5f7deccf88f28bfc8bMarco Nelissen return prop != null && prop.equals("true"); 416e4eb4d9de37a8e9ed6f43a5f7deccf88f28bfc8bMarco Nelissen } 417fbc4939d2b51d511858846363bf02c7c9f851ed2Mike Lockwood 4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private class MyMediaScannerClient implements MediaScannerClient { 41920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String mArtist; 4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String mAlbumArtist; // use this if mArtist is missing 4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String mAlbum; 4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String mTitle; 4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String mComposer; 4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String mGenre; 4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String mMimeType; 4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mFileType; 4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mTrack; 4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mYear; 4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mDuration; 4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String mPath; 4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private long mLastModified; 4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private long mFileSize; 434c9706f0262a2f399f95e0d78ba2b7616e08d0069Sahil Sachdeva private String mWriter; 435f679ba7d944a403fbdc77926c44978ffd5161f2dMarco Nelissen private int mCompilation; 43682428a862f325238cfb5646bbd65de3f1a11e7ccGloria Wang private boolean mIsDrm; 437997354e4b4a9666cedd62282471e97822affced9Mike Lockwood private boolean mNoMedia; // flag to suppress file from appearing in media tables 438e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang private int mWidth; 439e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang private int mHeight; 44020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 44158ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen public FileEntry beginFile(String path, String mimeType, long lastModified, 442997354e4b4a9666cedd62282471e97822affced9Mike Lockwood long fileSize, boolean isDirectory, boolean noMedia) { 443076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood mMimeType = mimeType; 444076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood mFileType = 0; 445076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood mFileSize = fileSize; 44659c14048bfc0a210077192410afa28ed6f85daa0Erik Almqvist mIsDrm = false; 44720b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 448076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood if (!isDirectory) { 449ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood if (!noMedia && isNoMediaFile(path)) { 450ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood noMedia = true; 4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 452997354e4b4a9666cedd62282471e97822affced9Mike Lockwood mNoMedia = noMedia; 45320b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 454076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood // try mimeType first, if it is specified 455076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood if (mimeType != null) { 456076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood mFileType = MediaFile.getFileTypeForMimeType(mimeType); 457076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood } 4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 459076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood // if mimeType was not specified, compute file type based on file extension. 460076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood if (mFileType == 0) { 461076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood MediaFile.MediaFileType mediaFileType = MediaFile.getFileType(path); 462076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood if (mediaFileType != null) { 463076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood mFileType = mediaFileType.fileType; 464076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood if (mMimeType == null) { 465076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood mMimeType = mediaFileType.mimeType; 466076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood } 467858caeaaa1db4076565e6df06b2b2721ec453c4eMike Lockwood } 4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 46920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 470076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood if (isDrmEnabled() && MediaFile.isDrmFileType(mFileType)) { 471076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood mFileType = getFileTypeFromDrm(path); 472076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood } 4735d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang } 4745d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang 47558ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen FileEntry entry = makeEntryFor(path); 476a8a656b0c595fa876a387a91f8813f88a2d3abe7Marco Nelissen // add some slack to avoid a rounding error 477a8a656b0c595fa876a387a91f8813f88a2d3abe7Marco Nelissen long delta = (entry != null) ? (lastModified - entry.mLastModified) : 0; 478a8a656b0c595fa876a387a91f8813f88a2d3abe7Marco Nelissen boolean wasModified = delta > 1 || delta < -1; 479a8a656b0c595fa876a387a91f8813f88a2d3abe7Marco Nelissen if (entry == null || wasModified) { 480a8a656b0c595fa876a387a91f8813f88a2d3abe7Marco Nelissen if (wasModified) { 481a8a656b0c595fa876a387a91f8813f88a2d3abe7Marco Nelissen entry.mLastModified = lastModified; 482a8a656b0c595fa876a387a91f8813f88a2d3abe7Marco Nelissen } else { 48358ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen entry = new FileEntry(0, path, lastModified, 484a8a656b0c595fa876a387a91f8813f88a2d3abe7Marco Nelissen (isDirectory ? MtpConstants.FORMAT_ASSOCIATION : 0)); 485a8a656b0c595fa876a387a91f8813f88a2d3abe7Marco Nelissen } 4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project entry.mLastModifiedChanged = true; 4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 48820b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mProcessPlaylists && MediaFile.isPlayListFileType(mFileType)) { 4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPlayLists.add(entry); 4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // we don't process playlists in the main scan, so return null 4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 49420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // clear all the metadata 4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mArtist = null; 4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAlbumArtist = null; 4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAlbum = null; 4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mTitle = null; 5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mComposer = null; 5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mGenre = null; 5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mTrack = 0; 5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mYear = 0; 5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDuration = 0; 5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPath = path; 5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLastModified = lastModified; 507c9706f0262a2f399f95e0d78ba2b7616e08d0069Sahil Sachdeva mWriter = null; 508f679ba7d944a403fbdc77926c44978ffd5161f2dMarco Nelissen mCompilation = 0; 509e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang mWidth = 0; 510e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang mHeight = 0; 51120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return entry; 5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 51420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 515bcbddd9342ee5ef48617ce7dcca6c505df3fcf08Marco Nelissen @Override 516997354e4b4a9666cedd62282471e97822affced9Mike Lockwood public void scanFile(String path, long lastModified, long fileSize, 517997354e4b4a9666cedd62282471e97822affced9Mike Lockwood boolean isDirectory, boolean noMedia) { 51800c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen // This is the callback funtion from native codes. 51900c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen // Log.v(TAG, "scanFile: "+path); 520997354e4b4a9666cedd62282471e97822affced9Mike Lockwood doScanFile(path, null, lastModified, fileSize, isDirectory, false, noMedia); 5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 523c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood public Uri doScanFile(String path, String mimeType, long lastModified, 524997354e4b4a9666cedd62282471e97822affced9Mike Lockwood long fileSize, boolean isDirectory, boolean scanAlways, boolean noMedia) { 5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Uri result = null; 5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// long t1 = System.currentTimeMillis(); 5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 52858ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen FileEntry entry = beginFile(path, mimeType, lastModified, 529997354e4b4a9666cedd62282471e97822affced9Mike Lockwood fileSize, isDirectory, noMedia); 53081e85bbf671f228600fba059e30cb22565bcfe9dMarco Nelissen 53181e85bbf671f228600fba059e30cb22565bcfe9dMarco Nelissen // if this file was just inserted via mtp, set the rowid to zero 53281e85bbf671f228600fba059e30cb22565bcfe9dMarco Nelissen // (even though it already exists in the database), to trigger 53381e85bbf671f228600fba059e30cb22565bcfe9dMarco Nelissen // the correct code path for updating its entry 53481e85bbf671f228600fba059e30cb22565bcfe9dMarco Nelissen if (mMtpObjectHandle != 0) { 53581e85bbf671f228600fba059e30cb22565bcfe9dMarco Nelissen entry.mRowId = 0; 53681e85bbf671f228600fba059e30cb22565bcfe9dMarco Nelissen } 5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // rescan for metadata if file was modified since last scan 5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (entry != null && (entry.mLastModifiedChanged || scanAlways)) { 539997354e4b4a9666cedd62282471e97822affced9Mike Lockwood if (noMedia) { 540997354e4b4a9666cedd62282471e97822affced9Mike Lockwood result = endFile(entry, false, false, false, false, false); 541997354e4b4a9666cedd62282471e97822affced9Mike Lockwood } else { 542dcb1a58cf9d66b36de825dae2fa0cb0529e60680Elliott Hughes String lowpath = path.toLowerCase(Locale.ROOT); 543997354e4b4a9666cedd62282471e97822affced9Mike Lockwood boolean ringtones = (lowpath.indexOf(RINGTONES_DIR) > 0); 544997354e4b4a9666cedd62282471e97822affced9Mike Lockwood boolean notifications = (lowpath.indexOf(NOTIFICATIONS_DIR) > 0); 545997354e4b4a9666cedd62282471e97822affced9Mike Lockwood boolean alarms = (lowpath.indexOf(ALARMS_DIR) > 0); 546997354e4b4a9666cedd62282471e97822affced9Mike Lockwood boolean podcasts = (lowpath.indexOf(PODCAST_DIR) > 0); 547997354e4b4a9666cedd62282471e97822affced9Mike Lockwood boolean music = (lowpath.indexOf(MUSIC_DIR) > 0) || 548997354e4b4a9666cedd62282471e97822affced9Mike Lockwood (!ringtones && !notifications && !alarms && !podcasts); 549997354e4b4a9666cedd62282471e97822affced9Mike Lockwood 550c861411d4bae0912054ff54c3efee90ae2db6db9Marco Nelissen boolean isaudio = MediaFile.isAudioFileType(mFileType); 551c861411d4bae0912054ff54c3efee90ae2db6db9Marco Nelissen boolean isvideo = MediaFile.isVideoFileType(mFileType); 552c861411d4bae0912054ff54c3efee90ae2db6db9Marco Nelissen boolean isimage = MediaFile.isImageFileType(mFileType); 553c861411d4bae0912054ff54c3efee90ae2db6db9Marco Nelissen 554c861411d4bae0912054ff54c3efee90ae2db6db9Marco Nelissen if (isaudio || isvideo || isimage) { 555c861411d4bae0912054ff54c3efee90ae2db6db9Marco Nelissen if (mExternalIsEmulated && path.startsWith(mExternalStoragePath)) { 556c861411d4bae0912054ff54c3efee90ae2db6db9Marco Nelissen // try to rewrite the path to bypass the sd card fuse layer 557c861411d4bae0912054ff54c3efee90ae2db6db9Marco Nelissen String directPath = Environment.getMediaStorageDirectory() + 558c861411d4bae0912054ff54c3efee90ae2db6db9Marco Nelissen path.substring(mExternalStoragePath.length()); 559c861411d4bae0912054ff54c3efee90ae2db6db9Marco Nelissen File f = new File(directPath); 560c861411d4bae0912054ff54c3efee90ae2db6db9Marco Nelissen if (f.exists()) { 561c861411d4bae0912054ff54c3efee90ae2db6db9Marco Nelissen path = directPath; 562c861411d4bae0912054ff54c3efee90ae2db6db9Marco Nelissen } 563c861411d4bae0912054ff54c3efee90ae2db6db9Marco Nelissen } 564c861411d4bae0912054ff54c3efee90ae2db6db9Marco Nelissen } 565c861411d4bae0912054ff54c3efee90ae2db6db9Marco Nelissen 566997354e4b4a9666cedd62282471e97822affced9Mike Lockwood // we only extract metadata for audio and video files 567c861411d4bae0912054ff54c3efee90ae2db6db9Marco Nelissen if (isaudio || isvideo) { 568997354e4b4a9666cedd62282471e97822affced9Mike Lockwood processFile(path, mimeType, this); 569997354e4b4a9666cedd62282471e97822affced9Mike Lockwood } 57020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 571c861411d4bae0912054ff54c3efee90ae2db6db9Marco Nelissen if (isimage) { 572e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang processImageFile(path); 573e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang } 574e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang 575997354e4b4a9666cedd62282471e97822affced9Mike Lockwood result = endFile(entry, ringtones, notifications, alarms, music, podcasts); 576997354e4b4a9666cedd62282471e97822affced9Mike Lockwood } 5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (RemoteException e) { 5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "RemoteException in MediaScanner.scanFile()", e); 5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// long t2 = System.currentTimeMillis(); 5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// Log.v(TAG, "scanFile: " + path + " took " + (t2-t1)); 5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return result; 5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int parseSubstring(String s, int start, int defaultValue) { 5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int length = s.length(); 5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (start == length) return defaultValue; 5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char ch = s.charAt(start++); 5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // return defaultValue if we have no integer at all 5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (ch < '0' || ch > '9') return defaultValue; 59320b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int result = ch - '0'; 5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (start < length) { 5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ch = s.charAt(start++); 5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (ch < '0' || ch > '9') return result; 5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project result = result * 10 + (ch - '0'); 5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 60020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return result; 60220b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync } 60320b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void handleStringTag(String name, String value) { 6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (name.equalsIgnoreCase("title") || name.startsWith("title;")) { 60673bb511adee5444ecd041146fbbd3677fb635949Marco Nelissen // Don't trim() here, to preserve the special \001 character 60773bb511adee5444ecd041146fbbd3677fb635949Marco Nelissen // used to force sorting. The media provider will trim() before 60873bb511adee5444ecd041146fbbd3677fb635949Marco Nelissen // inserting the title in to the database. 60973bb511adee5444ecd041146fbbd3677fb635949Marco Nelissen mTitle = value; 6109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (name.equalsIgnoreCase("artist") || name.startsWith("artist;")) { 6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mArtist = value.trim(); 612ed8188711a794867b47d21bbed3e26827f6c27e3Neel Parekh } else if (name.equalsIgnoreCase("albumartist") || name.startsWith("albumartist;") 613ed8188711a794867b47d21bbed3e26827f6c27e3Neel Parekh || name.equalsIgnoreCase("band") || name.startsWith("band;")) { 6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAlbumArtist = value.trim(); 6159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (name.equalsIgnoreCase("album") || name.startsWith("album;")) { 6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAlbum = value.trim(); 6179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (name.equalsIgnoreCase("composer") || name.startsWith("composer;")) { 6189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mComposer = value.trim(); 61943b076bb75e86fbb34cbe36aa0298c7a647121ffMike Lockwood } else if (mProcessGenres && 62043b076bb75e86fbb34cbe36aa0298c7a647121ffMike Lockwood (name.equalsIgnoreCase("genre") || name.startsWith("genre;"))) { 621cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen mGenre = getGenreName(value); 6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (name.equalsIgnoreCase("year") || name.startsWith("year;")) { 6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mYear = parseSubstring(value, 0, 0); 6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (name.equalsIgnoreCase("tracknumber") || name.startsWith("tracknumber;")) { 6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // track number might be of the form "2/12" 6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // we just read the number before the slash 6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int num = parseSubstring(value, 0, 0); 62820b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync mTrack = (mTrack / 1000) * 1000 + num; 6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (name.equalsIgnoreCase("discnumber") || 6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project name.equals("set") || name.startsWith("set;")) { 6319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // set number might be of the form "1/3" 6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // we just read the number before the slash 6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int num = parseSubstring(value, 0, 0); 6349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mTrack = (num * 1000) + (mTrack % 1000); 6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (name.equalsIgnoreCase("duration")) { 6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDuration = parseSubstring(value, 0, 0); 637c9706f0262a2f399f95e0d78ba2b7616e08d0069Sahil Sachdeva } else if (name.equalsIgnoreCase("writer") || name.startsWith("writer;")) { 638c9706f0262a2f399f95e0d78ba2b7616e08d0069Sahil Sachdeva mWriter = value.trim(); 639f679ba7d944a403fbdc77926c44978ffd5161f2dMarco Nelissen } else if (name.equalsIgnoreCase("compilation")) { 640f679ba7d944a403fbdc77926c44978ffd5161f2dMarco Nelissen mCompilation = parseSubstring(value, 0, 0); 64182428a862f325238cfb5646bbd65de3f1a11e7ccGloria Wang } else if (name.equalsIgnoreCase("isdrm")) { 64282428a862f325238cfb5646bbd65de3f1a11e7ccGloria Wang mIsDrm = (parseSubstring(value, 0, 0) == 1); 643e313f721ad97ad44666dd066a891acb4ddfa8ab3Marco Nelissen } else if (name.equalsIgnoreCase("width")) { 644e313f721ad97ad44666dd066a891acb4ddfa8ab3Marco Nelissen mWidth = parseSubstring(value, 0, 0); 645e313f721ad97ad44666dd066a891acb4ddfa8ab3Marco Nelissen } else if (name.equalsIgnoreCase("height")) { 646e313f721ad97ad44666dd066a891acb4ddfa8ab3Marco Nelissen mHeight = parseSubstring(value, 0, 0); 647ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen } else { 648ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen //Log.v(TAG, "unknown tag: " + name + " (" + mProcessGenres + ")"); 6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 65120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 652ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen private boolean convertGenreCode(String input, String expected) { 653ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen String output = getGenreName(input); 654ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen if (output.equals(expected)) { 655ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen return true; 656ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen } else { 657ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen Log.d(TAG, "'" + input + "' -> '" + output + "', expected '" + expected + "'"); 658ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen return false; 659ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen } 660ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen } 661ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen private void testGenreNameConverter() { 662ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen convertGenreCode("2", "Country"); 663ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen convertGenreCode("(2)", "Country"); 664ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen convertGenreCode("(2", "(2"); 665ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen convertGenreCode("2 Foo", "Country"); 666ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen convertGenreCode("(2) Foo", "Country"); 667ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen convertGenreCode("(2 Foo", "(2 Foo"); 668ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen convertGenreCode("2Foo", "2Foo"); 669ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen convertGenreCode("(2)Foo", "Country"); 670ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen convertGenreCode("200 Foo", "Foo"); 671ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen convertGenreCode("(200) Foo", "Foo"); 672ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen convertGenreCode("200Foo", "200Foo"); 673ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen convertGenreCode("(200)Foo", "Foo"); 674ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen convertGenreCode("200)Foo", "200)Foo"); 675ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen convertGenreCode("200) Foo", "200) Foo"); 676ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen } 677ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen 678cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen public String getGenreName(String genreTagValue) { 679cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen 680cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen if (genreTagValue == null) { 681cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen return null; 682cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen } 683cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen final int length = genreTagValue.length(); 684cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen 685ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen if (length > 0) { 686ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen boolean parenthesized = false; 687cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen StringBuffer number = new StringBuffer(); 688ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen int i = 0; 689ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen for (; i < length; ++i) { 690cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen char c = genreTagValue.charAt(i); 691ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen if (i == 0 && c == '(') { 692ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen parenthesized = true; 693ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen } else if (Character.isDigit(c)) { 694cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen number.append(c); 695cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen } else { 696cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen break; 697cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen } 698cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen } 699ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen char charAfterNumber = i < length ? genreTagValue.charAt(i) : ' '; 700ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen if ((parenthesized && charAfterNumber == ')') 701ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen || !parenthesized && Character.isWhitespace(charAfterNumber)) { 702cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen try { 703cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen short genreIndex = Short.parseShort(number.toString()); 704cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen if (genreIndex >= 0) { 705c3ea477e2111f199d10341b121791cb2ec91eca3Johan Redestig if (genreIndex < ID3_GENRES.length && ID3_GENRES[genreIndex] != null) { 706cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen return ID3_GENRES[genreIndex]; 707cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen } else if (genreIndex == 0xFF) { 708cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen return null; 709cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen } else if (genreIndex < 0xFF && (i + 1) < length) { 710cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen // genre is valid but unknown, 711cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen // if there is a string after the value we take it 712ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen if (parenthesized && charAfterNumber == ')') { 713ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen i++; 714ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen } 715ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen String ret = genreTagValue.substring(i).trim(); 716ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen if (ret.length() != 0) { 717ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen return ret; 718ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen } 719cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen } else { 720cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen // else return the number, without parentheses 721cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen return number.toString(); 722cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen } 723cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen } 724cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen } catch (NumberFormatException e) { 725cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen } 726cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen } 727cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen } 728cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen 729cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen return genreTagValue; 730cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen } 731cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen 732e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang private void processImageFile(String path) { 733e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang try { 734e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang mBitmapOptions.outWidth = 0; 735e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang mBitmapOptions.outHeight = 0; 736e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang BitmapFactory.decodeFile(path, mBitmapOptions); 737e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang mWidth = mBitmapOptions.outWidth; 738e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang mHeight = mBitmapOptions.outHeight; 739e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang } catch (Throwable th) { 740e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang // ignore; 741e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang } 742e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang } 743e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang 7449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setMimeType(String mimeType) { 7451851db6804cbdf8d2c8ede0725e73be6fda0f3c0Marco Nelissen if ("audio/mp4".equals(mMimeType) && 7461851db6804cbdf8d2c8ede0725e73be6fda0f3c0Marco Nelissen mimeType.startsWith("video")) { 7471851db6804cbdf8d2c8ede0725e73be6fda0f3c0Marco Nelissen // for feature parity with Donut, we force m4a files to keep the 7481851db6804cbdf8d2c8ede0725e73be6fda0f3c0Marco Nelissen // audio/mp4 mimetype, even if they are really "enhanced podcasts" 7491851db6804cbdf8d2c8ede0725e73be6fda0f3c0Marco Nelissen // with a video track 7501851db6804cbdf8d2c8ede0725e73be6fda0f3c0Marco Nelissen return; 7511851db6804cbdf8d2c8ede0725e73be6fda0f3c0Marco Nelissen } 7529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMimeType = mimeType; 7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mFileType = MediaFile.getFileTypeForMimeType(mimeType); 7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 75520b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 7569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Formats the data into a values array suitable for use with the Media 7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Content Provider. 75920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync * 7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return a map of values 7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private ContentValues toValues() { 7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ContentValues map = new ContentValues(); 7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project map.put(MediaStore.MediaColumns.DATA, mPath); 7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project map.put(MediaStore.MediaColumns.TITLE, mTitle); 7679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project map.put(MediaStore.MediaColumns.DATE_MODIFIED, mLastModified); 7689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project map.put(MediaStore.MediaColumns.SIZE, mFileSize); 7699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project map.put(MediaStore.MediaColumns.MIME_TYPE, mMimeType); 77082428a862f325238cfb5646bbd65de3f1a11e7ccGloria Wang map.put(MediaStore.MediaColumns.IS_DRM, mIsDrm); 77120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 772e313f721ad97ad44666dd066a891acb4ddfa8ab3Marco Nelissen String resolution = null; 773e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang if (mWidth > 0 && mHeight > 0) { 774e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang map.put(MediaStore.MediaColumns.WIDTH, mWidth); 775e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang map.put(MediaStore.MediaColumns.HEIGHT, mHeight); 776e313f721ad97ad44666dd066a891acb4ddfa8ab3Marco Nelissen resolution = mWidth + "x" + mHeight; 777e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang } 778e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang 779e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood if (!mNoMedia) { 780997354e4b4a9666cedd62282471e97822affced9Mike Lockwood if (MediaFile.isVideoFileType(mFileType)) { 781997354e4b4a9666cedd62282471e97822affced9Mike Lockwood map.put(Video.Media.ARTIST, (mArtist != null && mArtist.length() > 0 782997354e4b4a9666cedd62282471e97822affced9Mike Lockwood ? mArtist : MediaStore.UNKNOWN_STRING)); 783997354e4b4a9666cedd62282471e97822affced9Mike Lockwood map.put(Video.Media.ALBUM, (mAlbum != null && mAlbum.length() > 0 784997354e4b4a9666cedd62282471e97822affced9Mike Lockwood ? mAlbum : MediaStore.UNKNOWN_STRING)); 785997354e4b4a9666cedd62282471e97822affced9Mike Lockwood map.put(Video.Media.DURATION, mDuration); 786e313f721ad97ad44666dd066a891acb4ddfa8ab3Marco Nelissen if (resolution != null) { 787e313f721ad97ad44666dd066a891acb4ddfa8ab3Marco Nelissen map.put(Video.Media.RESOLUTION, resolution); 788e313f721ad97ad44666dd066a891acb4ddfa8ab3Marco Nelissen } 789997354e4b4a9666cedd62282471e97822affced9Mike Lockwood } else if (MediaFile.isImageFileType(mFileType)) { 790997354e4b4a9666cedd62282471e97822affced9Mike Lockwood // FIXME - add DESCRIPTION 791997354e4b4a9666cedd62282471e97822affced9Mike Lockwood } else if (MediaFile.isAudioFileType(mFileType)) { 792997354e4b4a9666cedd62282471e97822affced9Mike Lockwood map.put(Audio.Media.ARTIST, (mArtist != null && mArtist.length() > 0) ? 793997354e4b4a9666cedd62282471e97822affced9Mike Lockwood mArtist : MediaStore.UNKNOWN_STRING); 794997354e4b4a9666cedd62282471e97822affced9Mike Lockwood map.put(Audio.Media.ALBUM_ARTIST, (mAlbumArtist != null && 795997354e4b4a9666cedd62282471e97822affced9Mike Lockwood mAlbumArtist.length() > 0) ? mAlbumArtist : null); 796997354e4b4a9666cedd62282471e97822affced9Mike Lockwood map.put(Audio.Media.ALBUM, (mAlbum != null && mAlbum.length() > 0) ? 797997354e4b4a9666cedd62282471e97822affced9Mike Lockwood mAlbum : MediaStore.UNKNOWN_STRING); 798997354e4b4a9666cedd62282471e97822affced9Mike Lockwood map.put(Audio.Media.COMPOSER, mComposer); 799e5d0495d5206167c597efcd81436a0f881f069f9Mike Lockwood map.put(Audio.Media.GENRE, mGenre); 800997354e4b4a9666cedd62282471e97822affced9Mike Lockwood if (mYear != 0) { 801997354e4b4a9666cedd62282471e97822affced9Mike Lockwood map.put(Audio.Media.YEAR, mYear); 802997354e4b4a9666cedd62282471e97822affced9Mike Lockwood } 803997354e4b4a9666cedd62282471e97822affced9Mike Lockwood map.put(Audio.Media.TRACK, mTrack); 804997354e4b4a9666cedd62282471e97822affced9Mike Lockwood map.put(Audio.Media.DURATION, mDuration); 805997354e4b4a9666cedd62282471e97822affced9Mike Lockwood map.put(Audio.Media.COMPILATION, mCompilation); 8069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return map; 8099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 81020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 81158ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen private Uri endFile(FileEntry entry, boolean ringtones, boolean notifications, 81220b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync boolean alarms, boolean music, boolean podcasts) 8139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throws RemoteException { 8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // update database 81520b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 816997354e4b4a9666cedd62282471e97822affced9Mike Lockwood // use album artist if artist is missing 8179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mArtist == null || mArtist.length() == 0) { 8189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mArtist = mAlbumArtist; 8199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ContentValues values = toValues(); 8229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String title = values.getAsString(MediaStore.MediaColumns.TITLE); 823bdc0e82f9c075edb67da4a2583e557824c280415Mike Lockwood if (title == null || TextUtils.isEmpty(title.trim())) { 824c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood title = MediaFile.getFileTitle(values.getAsString(MediaStore.MediaColumns.DATA)); 8259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project values.put(MediaStore.MediaColumns.TITLE, title); 8269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 827c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen String album = values.getAsString(Audio.Media.ALBUM); 8289a488b44cb479bc42375d2cfcdd4aa6161dc17cfMarco Nelissen if (MediaStore.UNKNOWN_STRING.equals(album)) { 829c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen album = values.getAsString(MediaStore.MediaColumns.DATA); 830c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen // extract last path segment before file name 831c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen int lastSlash = album.lastIndexOf('/'); 832c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen if (lastSlash >= 0) { 833c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen int previousSlash = 0; 834c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen while (true) { 835c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen int idx = album.indexOf('/', previousSlash + 1); 836c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen if (idx < 0 || idx >= lastSlash) { 837c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen break; 838c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen } 839c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen previousSlash = idx; 840c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen } 841c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen if (previousSlash != 0) { 842c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen album = album.substring(previousSlash + 1, lastSlash); 843c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen values.put(Audio.Media.ALBUM, album); 844c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen } 845c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen } 846c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen } 847c066557378c2305625a7bad3d25f084ad647ef27Marco Nelissen long rowId = entry.mRowId; 848c2206a0710a3ca2c29854c1a0638c5ba55629ba2Mike Lockwood if (MediaFile.isAudioFileType(mFileType) && (rowId == 0 || mMtpObjectHandle != 0)) { 849c066557378c2305625a7bad3d25f084ad647ef27Marco Nelissen // Only set these for new entries. For existing entries, they 850c066557378c2305625a7bad3d25f084ad647ef27Marco Nelissen // may have been modified later, and we want to keep the current 851c066557378c2305625a7bad3d25f084ad647ef27Marco Nelissen // values so that custom ringtones still show up in the ringtone 852c066557378c2305625a7bad3d25f084ad647ef27Marco Nelissen // picker. 8539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project values.put(Audio.Media.IS_RINGTONE, ringtones); 8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project values.put(Audio.Media.IS_NOTIFICATION, notifications); 8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project values.put(Audio.Media.IS_ALARM, alarms); 8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project values.put(Audio.Media.IS_MUSIC, music); 8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project values.put(Audio.Media.IS_PODCAST, podcasts); 858997354e4b4a9666cedd62282471e97822affced9Mike Lockwood } else if (mFileType == MediaFile.FILE_TYPE_JPEG && !mNoMedia) { 859700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang ExifInterface exif = null; 860700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang try { 861700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang exif = new ExifInterface(entry.mPath); 862700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang } catch (IOException ex) { 863700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang // exif is null 864700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang } 865700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang if (exif != null) { 866872a30ec723ebdd97de764406544516545d7c9d4Chih-Chung Chang float[] latlng = new float[2]; 867872a30ec723ebdd97de764406544516545d7c9d4Chih-Chung Chang if (exif.getLatLong(latlng)) { 86820b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync values.put(Images.Media.LATITUDE, latlng[0]); 86920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync values.put(Images.Media.LONGITUDE, latlng[1]); 87020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync } 871099397cbd07c8c991f3126d0d0ac64bb6b3c0b47Chih-Chung Chang 8723a8cab88e7747dc280ce85895af014f98e80a6ccRay Chen long time = exif.getGpsDateTime(); 873099397cbd07c8c991f3126d0d0ac64bb6b3c0b47Chih-Chung Chang if (time != -1) { 874052d9c8b414dc9eb1c70d849660592d9bc3b2644Ray Chen values.put(Images.Media.DATE_TAKEN, time); 875a2c322f599b5a44ca153922b994a05a4311331cbRay Chen } else { 876a2c322f599b5a44ca153922b994a05a4311331cbRay Chen // If no time zone information is available, we should consider using 877a2c322f599b5a44ca153922b994a05a4311331cbRay Chen // EXIF local time as taken time if the difference between file time 878a2c322f599b5a44ca153922b994a05a4311331cbRay Chen // and EXIF local time is not less than 1 Day, otherwise MediaProvider 879a2c322f599b5a44ca153922b994a05a4311331cbRay Chen // will use file time as taken time. 880a2c322f599b5a44ca153922b994a05a4311331cbRay Chen time = exif.getDateTime(); 881872e7b7073fad8295e6314c73b87d7cb3f85d39cRay Chen if (time != -1 && Math.abs(mLastModified * 1000 - time) >= 86400000) { 882a2c322f599b5a44ca153922b994a05a4311331cbRay Chen values.put(Images.Media.DATE_TAKEN, time); 883a2c322f599b5a44ca153922b994a05a4311331cbRay Chen } 884099397cbd07c8c991f3126d0d0ac64bb6b3c0b47Chih-Chung Chang } 885b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang 886b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang int orientation = exif.getAttributeInt( 887b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang ExifInterface.TAG_ORIENTATION, -1); 888b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang if (orientation != -1) { 889b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang // We only recognize a subset of orientation tag values. 890b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang int degree; 891b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang switch(orientation) { 892b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang case ExifInterface.ORIENTATION_ROTATE_90: 893b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang degree = 90; 894b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang break; 895b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang case ExifInterface.ORIENTATION_ROTATE_180: 896b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang degree = 180; 897b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang break; 898b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang case ExifInterface.ORIENTATION_ROTATE_270: 899b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang degree = 270; 900b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang break; 901b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang default: 902b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang degree = 0; 903b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang break; 904b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang } 905b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang values.put(Images.Media.ORIENTATION, degree); 906b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang } 90720b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync } 9089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 90920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 91045aaa2a345292bb6d600822db602f25e261c0e50Mike Lockwood Uri tableUri = mFilesUri; 9118e2ed8d512ade2ea481b3a292556782b17a74674Dongwon Kang MediaInserter inserter = mMediaInserter; 912e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood if (!mNoMedia) { 913e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood if (MediaFile.isVideoFileType(mFileType)) { 914e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood tableUri = mVideoUri; 915e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood } else if (MediaFile.isImageFileType(mFileType)) { 916e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood tableUri = mImagesUri; 917e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood } else if (MediaFile.isAudioFileType(mFileType)) { 918e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood tableUri = mAudioUri; 919e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood } 920e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood } 9219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Uri result = null; 9226c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim boolean needToSetSettings = false; 9239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (rowId == 0) { 924c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood if (mMtpObjectHandle != 0) { 925c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood values.put(MediaStore.MediaColumns.MEDIA_SCANNER_NEW_OBJECT_ID, mMtpObjectHandle); 926c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood } 927e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood if (tableUri == mFilesUri) { 928e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood int format = entry.mFormat; 929e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood if (format == 0) { 930e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood format = MediaFile.getFormatCode(entry.mPath, mMimeType); 931e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood } 932e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood values.put(Files.FileColumns.FORMAT, format); 933c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood } 9346c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim // Setting a flag in order not to use bulk insert for the file related with 9356c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim // notifications, ringtones, and alarms, because the rowId of the inserted file is 9366c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim // needed. 9376c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim if (mWasEmptyPriorToScan) { 9386c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim if (notifications && !mDefaultNotificationSet) { 9396c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim if (TextUtils.isEmpty(mDefaultNotificationFilename) || 9406c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim doesPathHaveFilename(entry.mPath, mDefaultNotificationFilename)) { 9416c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim needToSetSettings = true; 9426c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim } 9436c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim } else if (ringtones && !mDefaultRingtoneSet) { 9446c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim if (TextUtils.isEmpty(mDefaultRingtoneFilename) || 9456c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim doesPathHaveFilename(entry.mPath, mDefaultRingtoneFilename)) { 9466c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim needToSetSettings = true; 9476c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim } 9486c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim } else if (alarms && !mDefaultAlarmSet) { 9496c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim if (TextUtils.isEmpty(mDefaultAlarmAlertFilename) || 9506c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim doesPathHaveFilename(entry.mPath, mDefaultAlarmAlertFilename)) { 9516c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim needToSetSettings = true; 9526c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim } 9536c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim } 9546c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim } 9556c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim 956d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen // New file, insert it. 957d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen // Directories need to be inserted before the files they contain, so they 958d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen // get priority when bulk inserting. 959d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen // If the rowId of the inserted file is needed, it gets inserted immediately, 960d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen // bypassing the bulk inserter. 961d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen if (inserter == null || needToSetSettings) { 962299942002b17f792e6e4f6b3f6972f62b8b136aeMarco Nelissen if (inserter != null) { 963299942002b17f792e6e4f6b3f6972f62b8b136aeMarco Nelissen inserter.flushAll(); 964299942002b17f792e6e4f6b3f6972f62b8b136aeMarco Nelissen } 96535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn result = mMediaProvider.insert(mPackageName, tableUri, values); 966d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen } else if (entry.mFormat == MtpConstants.FORMAT_ASSOCIATION) { 967d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen inserter.insertwithPriority(tableUri, values); 968c6eaa713a3f5b9337eca60ba2ab570cf6e80c357Mike Lockwood } else { 9698e2ed8d512ade2ea481b3a292556782b17a74674Dongwon Kang inserter.insert(tableUri, values); 970bd682b040833fce9e212c00c395b32bec7050f87Mike Lockwood } 971bd682b040833fce9e212c00c395b32bec7050f87Mike Lockwood 9729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (result != null) { 9739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project rowId = ContentUris.parseId(result); 9749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project entry.mRowId = rowId; 9759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 9779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // updated file 97845aaa2a345292bb6d600822db602f25e261c0e50Mike Lockwood result = ContentUris.withAppendedId(tableUri, rowId); 9790dd9f4de3ed681e83bd79ddcd4fd463093d11ed3Mike Lockwood // path should never change, and we want to avoid replacing mixed cased paths 9800dd9f4de3ed681e83bd79ddcd4fd463093d11ed3Mike Lockwood // with squashed lower case paths 9810dd9f4de3ed681e83bd79ddcd4fd463093d11ed3Mike Lockwood values.remove(MediaStore.MediaColumns.DATA); 982ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen 983ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen int mediaType = 0; 984ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen if (!MediaScanner.isNoMediaPath(entry.mPath)) { 985ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen int fileType = MediaFile.getFileTypeForMimeType(mMimeType); 986ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen if (MediaFile.isAudioFileType(fileType)) { 987ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen mediaType = FileColumns.MEDIA_TYPE_AUDIO; 988ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen } else if (MediaFile.isVideoFileType(fileType)) { 989ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen mediaType = FileColumns.MEDIA_TYPE_VIDEO; 990ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen } else if (MediaFile.isImageFileType(fileType)) { 991ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen mediaType = FileColumns.MEDIA_TYPE_IMAGE; 992ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen } else if (MediaFile.isPlayListFileType(fileType)) { 993ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen mediaType = FileColumns.MEDIA_TYPE_PLAYLIST; 994ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen } 995ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen values.put(FileColumns.MEDIA_TYPE, mediaType); 996ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen } 99735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn mMediaProvider.update(mPackageName, result, values, null, null); 9989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 99920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 10006c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim if(needToSetSettings) { 10016c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim if (notifications) { 100245aaa2a345292bb6d600822db602f25e261c0e50Mike Lockwood setSettingIfNotSet(Settings.System.NOTIFICATION_SOUND, tableUri, rowId); 10039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDefaultNotificationSet = true; 10046c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim } else if (ringtones) { 100545aaa2a345292bb6d600822db602f25e261c0e50Mike Lockwood setSettingIfNotSet(Settings.System.RINGTONE, tableUri, rowId); 10069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDefaultRingtoneSet = true; 10076c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim } else if (alarms) { 100845aaa2a345292bb6d600822db602f25e261c0e50Mike Lockwood setSettingIfNotSet(Settings.System.ALARM_ALERT, tableUri, rowId); 10093156bb00dd3ab3d6ec732bb6a64a2e84d08c34f0Patrick Scott mDefaultAlarmSet = true; 10103156bb00dd3ab3d6ec732bb6a64a2e84d08c34f0Patrick Scott } 10119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 101220b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 10139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return result; 10149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 101520b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 10169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean doesPathHaveFilename(String path, String filename) { 10179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int pathFilenameStart = path.lastIndexOf(File.separatorChar) + 1; 10189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int filenameLength = filename.length(); 10199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return path.regionMatches(pathFilenameStart, filename, 0, filenameLength) && 10209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project pathFilenameStart + filenameLength == path.length(); 10219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 102220b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 10239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void setSettingIfNotSet(String settingName, Uri uri, long rowId) { 102420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 10259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String existingSettingValue = Settings.System.getString(mContext.getContentResolver(), 10269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project settingName); 102720b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 10289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (TextUtils.isEmpty(existingSettingValue)) { 10299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Set the setting to the given URI 10309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Settings.System.putString(mContext.getContentResolver(), settingName, 10319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ContentUris.withAppendedId(uri, rowId).toString()); 10329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 103420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 10355d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang private int getFileTypeFromDrm(String path) { 1036e4eb4d9de37a8e9ed6f43a5f7deccf88f28bfc8bMarco Nelissen if (!isDrmEnabled()) { 10375d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang return 0; 10385d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang } 10395d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang 10405d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang int resultFileType = 0; 10415d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang 10425d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang if (mDrmManagerClient == null) { 10435d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang mDrmManagerClient = new DrmManagerClient(mContext); 10445d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang } 10455d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang 10465d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang if (mDrmManagerClient.canHandle(path, null)) { 104759c14048bfc0a210077192410afa28ed6f85daa0Erik Almqvist mIsDrm = true; 10485d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang String drmMimetype = mDrmManagerClient.getOriginalMimeType(path); 10495d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang if (drmMimetype != null) { 10505d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang mMimeType = drmMimetype; 10515d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang resultFileType = MediaFile.getFileTypeForMimeType(drmMimetype); 10525d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang } 10535d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang } 10545d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang return resultFileType; 10555d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang } 10565d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang 10579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; // end of anonymous MediaScannerClient instance 105820b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 1059c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood private void prescan(String filePath, boolean prescanFiles) throws RemoteException { 10609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Cursor c = null; 10619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String where = null; 10629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String[] selectionArgs = null; 106320b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 10649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mPlayLists == null) { 106558ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen mPlayLists = new ArrayList<FileEntry>(); 10669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 10679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPlayLists.clear(); 10689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 106920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 1070c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood if (filePath != null) { 1071c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood // query for only one file 107258ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen where = MediaStore.Files.FileColumns._ID + ">?" + 107358ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen " AND " + Files.FileColumns.DATA + "=?"; 107458ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen selectionArgs = new String[] { "", filePath }; 107558ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen } else { 107658ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen where = MediaStore.Files.FileColumns._ID + ">?"; 107758ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen selectionArgs = new String[] { "" }; 1078c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood } 1079c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood 108058ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen // Tell the provider to not delete the file. 108158ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen // If the file is truly gone the delete is unnecessary, and we want to avoid 108258ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen // accidentally deleting files that are really there (this may happen if the 108358ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen // filesystem is mounted and unmounted while the scanner is running). 108458ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen Uri.Builder builder = mFilesUri.buildUpon(); 108558ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen builder.appendQueryParameter(MediaStore.PARAM_DELETE_DATA, "false"); 108635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn MediaBulkDeleter deleter = new MediaBulkDeleter(mMediaProvider, mPackageName, 108735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn builder.build()); 108858ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen 10899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Build the list of files from the content provider 10909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 1091c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood if (prescanFiles) { 109258ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen // First read existing files from the files table. 109358ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen // Because we'll be deleting entries for missing files as we go, 109458ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen // we need to query the database in small batches, to avoid problems 109558ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen // with CursorWindow positioning. 109658ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen long lastId = Long.MIN_VALUE; 109758ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen Uri limitUri = mFilesUri.buildUpon().appendQueryParameter("limit", "1000").build(); 109858ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen mWasEmptyPriorToScan = true; 109958ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen 110058ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen while (true) { 110158ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen selectionArgs[0] = "" + lastId; 110258ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen if (c != null) { 110358ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen c.close(); 110458ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen c = null; 110558ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen } 110635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn c = mMediaProvider.query(mPackageName, limitUri, FILES_PRESCAN_PROJECTION, 110758ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen where, selectionArgs, MediaStore.Files.FileColumns._ID, null); 110858ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen if (c == null) { 110958ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen break; 111058ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen } 111120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 111258ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen int num = c.getCount(); 1113c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood 111458ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen if (num == 0) { 111558ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen break; 111658ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen } 111758ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen mWasEmptyPriorToScan = false; 11189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (c.moveToNext()) { 1119d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood long rowId = c.getLong(FILES_PRESCAN_ID_COLUMN_INDEX); 1120d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood String path = c.getString(FILES_PRESCAN_PATH_COLUMN_INDEX); 1121d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood int format = c.getInt(FILES_PRESCAN_FORMAT_COLUMN_INDEX); 1122d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood long lastModified = c.getLong(FILES_PRESCAN_DATE_MODIFIED_COLUMN_INDEX); 112358ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen lastId = rowId; 112420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 112535b002a9c873fb40116179c8626b9841b0abae74Marco Nelissen // Only consider entries with absolute path names. 112635b002a9c873fb40116179c8626b9841b0abae74Marco Nelissen // This allows storing URIs in the database without the 112735b002a9c873fb40116179c8626b9841b0abae74Marco Nelissen // media scanner removing them. 11283e5e8055942ee8179675b8ed11d40ca12dbe42e6Marco Nelissen if (path != null && path.startsWith("/")) { 112958ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen boolean exists = false; 113058ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen try { 113134385d352da19805ae948215e2edbeedd16b7941Elliott Hughes exists = Os.access(path, android.system.OsConstants.F_OK); 113258ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen } catch (ErrnoException e1) { 113358ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen } 113458ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen if (!exists && !MtpConstants.isAbstractObject(format)) { 113558ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen // do not delete missing playlists, since they may have been 113658ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen // modified by the user. 113758ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen // The user can delete them in the media player instead. 113858ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen // instead, clear the path and lastModified fields in the row 113958ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen MediaFile.MediaFileType mediaFileType = MediaFile.getFileType(path); 114058ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen int fileType = (mediaFileType == null ? 0 : mediaFileType.fileType); 114158ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen 114258ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen if (!MediaFile.isPlayListFileType(fileType)) { 114358ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen deleter.delete(rowId); 114458ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen if (path.toLowerCase(Locale.US).endsWith("/.nomedia")) { 114558ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen deleter.flush(); 114658ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen String parent = new File(path).getParent(); 114735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn mMediaProvider.call(mPackageName, MediaStore.UNHIDE_CALL, 114835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn parent, null); 114958ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen } 115058ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen } 115135b002a9c873fb40116179c8626b9841b0abae74Marco Nelissen } 11529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project finally { 11589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (c != null) { 11599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project c.close(); 11609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 116158ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen deleter.flush(); 11629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11636458935331ccfacb4cccc50d6b893947febae687Mike Lockwood 11646458935331ccfacb4cccc50d6b893947febae687Mike Lockwood // compute original size of images 11656458935331ccfacb4cccc50d6b893947febae687Mike Lockwood mOriginalCount = 0; 116635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn c = mMediaProvider.query(mPackageName, mImagesUri, ID_PROJECTION, null, null, null, null); 11676458935331ccfacb4cccc50d6b893947febae687Mike Lockwood if (c != null) { 11686458935331ccfacb4cccc50d6b893947febae687Mike Lockwood mOriginalCount = c.getCount(); 11696458935331ccfacb4cccc50d6b893947febae687Mike Lockwood c.close(); 11706458935331ccfacb4cccc50d6b893947febae687Mike Lockwood } 11719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 117220b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 11739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean inScanDirectory(String path, String[] directories) { 11749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < directories.length; i++) { 1175f45853af5051df4abaa33cdca7fa986104811d1aMike Lockwood String directory = directories[i]; 1176f45853af5051df4abaa33cdca7fa986104811d1aMike Lockwood if (path.startsWith(directory)) { 11779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 11789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 11819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 118220b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 11839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void pruneDeadThumbnailFiles() { 11849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project HashSet<String> existingFiles = new HashSet<String>(); 11859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String directory = "/sdcard/DCIM/.thumbnails"; 11869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String [] files = (new File(directory)).list(); 1187f3fd18d1b4cb44bb31a5b4fba26136f6f4fc37adMattias Nilsson Cursor c = null; 11889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (files == null) 11899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project files = new String[0]; 119020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 11919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < files.length; i++) { 11929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String fullPathString = directory + "/" + files[i]; 11939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project existingFiles.add(fullPathString); 11949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 119520b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 11969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 1197f3fd18d1b4cb44bb31a5b4fba26136f6f4fc37adMattias Nilsson c = mMediaProvider.query( 119835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn mPackageName, 119920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync mThumbsUri, 120020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync new String [] { "_data" }, 120120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync null, 120220b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync null, 120375ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown null, null); 12049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.v(TAG, "pruneDeadThumbnailFiles... " + c); 12059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (c != null && c.moveToFirst()) { 12069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project do { 12079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String fullPathString = c.getString(0); 12089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project existingFiles.remove(fullPathString); 12099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } while (c.moveToNext()); 12109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 121120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 12129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (String fileToDelete : existingFiles) { 121343a17654cf4bfe7f1ec22bd8b7b32daccdf27c09Joe Onorato if (false) 12149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.v(TAG, "fileToDelete is " + fileToDelete); 12159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 12169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (new File(fileToDelete)).delete(); 12179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (SecurityException ex) { 12189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 122020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 12219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.v(TAG, "/pruneDeadThumbnailFiles... " + c); 1222f3fd18d1b4cb44bb31a5b4fba26136f6f4fc37adMattias Nilsson } catch (RemoteException e) { 1223f3fd18d1b4cb44bb31a5b4fba26136f6f4fc37adMattias Nilsson // We will soon be killed... 1224f3fd18d1b4cb44bb31a5b4fba26136f6f4fc37adMattias Nilsson } finally { 12259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (c != null) { 12269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project c.close(); 12279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12319ff4774cac499a376a59373d5bfb5112c9a2a004Marco Nelissen static class MediaBulkDeleter { 1232d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen StringBuilder whereClause = new StringBuilder(); 1233872e7b7073fad8295e6314c73b87d7cb3f85d39cRay Chen ArrayList<String> whereArgs = new ArrayList<String>(100); 123435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn final IContentProvider mProvider; 123535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn final String mPackageName; 123635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn final Uri mBaseUri; 12379ff4774cac499a376a59373d5bfb5112c9a2a004Marco Nelissen 123835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn public MediaBulkDeleter(IContentProvider provider, String packageName, Uri baseUri) { 12399ff4774cac499a376a59373d5bfb5112c9a2a004Marco Nelissen mProvider = provider; 124035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn mPackageName = packageName; 12419ff4774cac499a376a59373d5bfb5112c9a2a004Marco Nelissen mBaseUri = baseUri; 12429ff4774cac499a376a59373d5bfb5112c9a2a004Marco Nelissen } 12439ff4774cac499a376a59373d5bfb5112c9a2a004Marco Nelissen 12449ff4774cac499a376a59373d5bfb5112c9a2a004Marco Nelissen public void delete(long id) throws RemoteException { 1245d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen if (whereClause.length() != 0) { 1246d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen whereClause.append(","); 12479ff4774cac499a376a59373d5bfb5112c9a2a004Marco Nelissen } 1248d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen whereClause.append("?"); 1249d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen whereArgs.add("" + id); 1250d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen if (whereArgs.size() > 100) { 12519ff4774cac499a376a59373d5bfb5112c9a2a004Marco Nelissen flush(); 12529ff4774cac499a376a59373d5bfb5112c9a2a004Marco Nelissen } 12539ff4774cac499a376a59373d5bfb5112c9a2a004Marco Nelissen } 12549ff4774cac499a376a59373d5bfb5112c9a2a004Marco Nelissen public void flush() throws RemoteException { 1255d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen int size = whereArgs.size(); 1256d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen if (size > 0) { 1257d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen String [] foo = new String [size]; 1258d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen foo = whereArgs.toArray(foo); 125935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn int numrows = mProvider.delete(mPackageName, mBaseUri, 126035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn MediaStore.MediaColumns._ID + " IN (" + 1261d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen whereClause.toString() + ")", foo); 1262d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen //Log.i("@@@@@@@@@", "rows deleted: " + numrows); 1263d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen whereClause.setLength(0); 1264d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen whereArgs.clear(); 1265d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen } 12669ff4774cac499a376a59373d5bfb5112c9a2a004Marco Nelissen } 12679ff4774cac499a376a59373d5bfb5112c9a2a004Marco Nelissen } 12689ff4774cac499a376a59373d5bfb5112c9a2a004Marco Nelissen 12699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void postscan(String[] directories) throws RemoteException { 127020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 12719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // handle playlists last, after we know what media files are on the storage. 12729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mProcessPlaylists) { 12739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project processPlayLists(); 12749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 127520b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 12769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mOriginalCount == 0 && mImagesUri.equals(Images.Media.getContentUri("external"))) 12779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project pruneDeadThumbnailFiles(); 127820b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 12799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // allow GC to clean up 12809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPlayLists = null; 12819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaProvider = null; 12829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 128320b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 12841b37c3bddcdfe7cb60e776e3eb05bfbb46b0b282Mattias Nilsson private void releaseResources() { 12851b37c3bddcdfe7cb60e776e3eb05bfbb46b0b282Mattias Nilsson // release the DrmManagerClient resources 12861b37c3bddcdfe7cb60e776e3eb05bfbb46b0b282Mattias Nilsson if (mDrmManagerClient != null) { 12871b37c3bddcdfe7cb60e776e3eb05bfbb46b0b282Mattias Nilsson mDrmManagerClient.release(); 12881b37c3bddcdfe7cb60e776e3eb05bfbb46b0b282Mattias Nilsson mDrmManagerClient = null; 12891b37c3bddcdfe7cb60e776e3eb05bfbb46b0b282Mattias Nilsson } 12901b37c3bddcdfe7cb60e776e3eb05bfbb46b0b282Mattias Nilsson } 12911b37c3bddcdfe7cb60e776e3eb05bfbb46b0b282Mattias Nilsson 12929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void initialize(String volumeName) { 12939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaProvider = mContext.getContentResolver().acquireProvider("media"); 129420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 12959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAudioUri = Audio.Media.getContentUri(volumeName); 12969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mVideoUri = Video.Media.getContentUri(volumeName); 12979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mImagesUri = Images.Media.getContentUri(volumeName); 12989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mThumbsUri = Images.Thumbnails.getContentUri(volumeName); 1299c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood mFilesUri = Files.getContentUri(volumeName); 13008ad76fa7a644c10abb7b95398fdb8a84bd723619Marco Nelissen mFilesUriNoNotify = mFilesUri.buildUpon().appendQueryParameter("nonotify", "1").build(); 13019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!volumeName.equals("internal")) { 13039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // we only support playlists on external media 13049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mProcessPlaylists = true; 130543b076bb75e86fbb34cbe36aa0298c7a647121ffMike Lockwood mProcessGenres = true; 13069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPlaylistsUri = Playlists.getContentUri(volumeName); 1307f73738b78a8396552274cf33b0021f414fb7201dMike Lockwood 1308f50e54e64b2b5a269e1a88c511a57064a14bb51bDianne Hackborn mCaseInsensitivePaths = true; 130920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync } 13109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void scanDirectories(String[] directories, String volumeName) { 13139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 13149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long start = System.currentTimeMillis(); 131520b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync initialize(volumeName); 1316c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood prescan(null, true); 13179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long prescan = System.currentTimeMillis(); 1318e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood 13193410b4656505673c72da558dcfec94d7b135e760Mike Lockwood if (ENABLE_BULK_INSERTS) { 13208e2ed8d512ade2ea481b3a292556782b17a74674Dongwon Kang // create MediaInserter for bulk inserts 132135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn mMediaInserter = new MediaInserter(mMediaProvider, mPackageName, 500); 13223410b4656505673c72da558dcfec94d7b135e760Mike Lockwood } 132320b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 13249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < directories.length; i++) { 1325c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood processDirectory(directories[i], mClient); 13269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1327e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood 13283410b4656505673c72da558dcfec94d7b135e760Mike Lockwood if (ENABLE_BULK_INSERTS) { 13293410b4656505673c72da558dcfec94d7b135e760Mike Lockwood // flush remaining inserts 13308e2ed8d512ade2ea481b3a292556782b17a74674Dongwon Kang mMediaInserter.flushAll(); 13318e2ed8d512ade2ea481b3a292556782b17a74674Dongwon Kang mMediaInserter = null; 13323410b4656505673c72da558dcfec94d7b135e760Mike Lockwood } 1333bd682b040833fce9e212c00c395b32bec7050f87Mike Lockwood 13349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long scan = System.currentTimeMillis(); 13359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project postscan(directories); 13369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long end = System.currentTimeMillis(); 133720b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 133843a17654cf4bfe7f1ec22bd8b7b32daccdf27c09Joe Onorato if (false) { 13399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.d(TAG, " prescan time: " + (prescan - start) + "ms\n"); 13409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.d(TAG, " scan time: " + (scan - prescan) + "ms\n"); 13419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.d(TAG, "postscan time: " + (end - scan) + "ms\n"); 13429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.d(TAG, " total time: " + (end - start) + "ms\n"); 13439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (SQLException e) { 13459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // this might happen if the SD card is removed while the media scanner is running 13469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "SQLException in MediaScanner.scan()", e); 13479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (UnsupportedOperationException e) { 13489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // this might happen if the SD card is removed while the media scanner is running 13499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "UnsupportedOperationException in MediaScanner.scan()", e); 13509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (RemoteException e) { 13519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "RemoteException in MediaScanner.scan()", e); 13521b37c3bddcdfe7cb60e776e3eb05bfbb46b0b282Mattias Nilsson } finally { 13531b37c3bddcdfe7cb60e776e3eb05bfbb46b0b282Mattias Nilsson releaseResources(); 13549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // this function is used to scan a single file 13589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Uri scanSingleFile(String path, String volumeName, String mimeType) { 13599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 136020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync initialize(volumeName); 1361c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood prescan(path, true); 136220b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 13639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project File file = new File(path); 1364348aa65e93c1b8cb409de12e3e61136f894201f2Marco Nelissen if (!file.exists()) { 1365348aa65e93c1b8cb409de12e3e61136f894201f2Marco Nelissen return null; 1366348aa65e93c1b8cb409de12e3e61136f894201f2Marco Nelissen } 1367ec74abb71f79cdc573c536115acc7ff26a02680aMikael 1368ec74abb71f79cdc573c536115acc7ff26a02680aMikael // lastModified is in milliseconds on Files. 1369ec74abb71f79cdc573c536115acc7ff26a02680aMikael long lastModifiedSeconds = file.lastModified() / 1000; 1370ec74abb71f79cdc573c536115acc7ff26a02680aMikael 13719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // always scan the file, so we can return the content://media Uri for existing files 13727a0bd17bceaf3efc3732e30c538fae420d3b742cMike Lockwood return mClient.doScanFile(path, mimeType, lastModifiedSeconds, file.length(), 137366dfcd465c02d78cb4ff22e7b509ee42d4309286Marco Nelissen false, true, MediaScanner.isNoMediaPath(path)); 13749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (RemoteException e) { 13759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "RemoteException in MediaScanner.scanFile()", e); 13769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 13771b37c3bddcdfe7cb60e776e3eb05bfbb46b0b282Mattias Nilsson } finally { 13781b37c3bddcdfe7cb60e776e3eb05bfbb46b0b282Mattias Nilsson releaseResources(); 13799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1382ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood private static boolean isNoMediaFile(String path) { 1383ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood File file = new File(path); 1384ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood if (file.isDirectory()) return false; 1385ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood 1386ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood // special case certain file names 1387ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood // I use regionMatches() instead of substring() below 1388ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood // to avoid memory allocation 1389ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood int lastSlash = path.lastIndexOf('/'); 1390ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood if (lastSlash >= 0 && lastSlash + 2 < path.length()) { 1391ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood // ignore those ._* files created by MacOS 1392ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood if (path.regionMatches(lastSlash + 1, "._", 0, 2)) { 1393ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood return true; 1394ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood } 1395ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood 1396ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood // ignore album art files created by Windows Media Player: 1397ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood // Folder.jpg, AlbumArtSmall.jpg, AlbumArt_{...}_Large.jpg 1398ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood // and AlbumArt_{...}_Small.jpg 1399ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood if (path.regionMatches(true, path.length() - 4, ".jpg", 0, 4)) { 1400ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood if (path.regionMatches(true, lastSlash + 1, "AlbumArt_{", 0, 10) || 1401ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood path.regionMatches(true, lastSlash + 1, "AlbumArt.", 0, 9)) { 1402ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood return true; 1403ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood } 1404ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood int length = path.length() - lastSlash - 1; 1405ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood if ((length == 17 && path.regionMatches( 1406ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood true, lastSlash + 1, "AlbumArtSmall", 0, 13)) || 1407ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood (length == 10 1408ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood && path.regionMatches(true, lastSlash + 1, "Folder", 0, 6))) { 1409ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood return true; 1410ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood } 1411ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood } 1412ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood } 1413ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood return false; 1414ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood } 1415ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood 1416997354e4b4a9666cedd62282471e97822affced9Mike Lockwood public static boolean isNoMediaPath(String path) { 1417997354e4b4a9666cedd62282471e97822affced9Mike Lockwood if (path == null) return false; 1418997354e4b4a9666cedd62282471e97822affced9Mike Lockwood 1419997354e4b4a9666cedd62282471e97822affced9Mike Lockwood // return true if file or any parent directory has name starting with a dot 1420997354e4b4a9666cedd62282471e97822affced9Mike Lockwood if (path.indexOf("/.") >= 0) return true; 1421997354e4b4a9666cedd62282471e97822affced9Mike Lockwood 1422997354e4b4a9666cedd62282471e97822affced9Mike Lockwood // now check to see if any parent directories have a ".nomedia" file 1423997354e4b4a9666cedd62282471e97822affced9Mike Lockwood // start from 1 so we don't bother checking in the root directory 1424997354e4b4a9666cedd62282471e97822affced9Mike Lockwood int offset = 1; 1425997354e4b4a9666cedd62282471e97822affced9Mike Lockwood while (offset >= 0) { 1426997354e4b4a9666cedd62282471e97822affced9Mike Lockwood int slashIndex = path.indexOf('/', offset); 1427997354e4b4a9666cedd62282471e97822affced9Mike Lockwood if (slashIndex > offset) { 1428997354e4b4a9666cedd62282471e97822affced9Mike Lockwood slashIndex++; // move past slash 1429997354e4b4a9666cedd62282471e97822affced9Mike Lockwood File file = new File(path.substring(0, slashIndex) + ".nomedia"); 1430997354e4b4a9666cedd62282471e97822affced9Mike Lockwood if (file.exists()) { 1431997354e4b4a9666cedd62282471e97822affced9Mike Lockwood // we have a .nomedia in one of the parent directories 1432997354e4b4a9666cedd62282471e97822affced9Mike Lockwood return true; 1433997354e4b4a9666cedd62282471e97822affced9Mike Lockwood } 1434997354e4b4a9666cedd62282471e97822affced9Mike Lockwood } 1435997354e4b4a9666cedd62282471e97822affced9Mike Lockwood offset = slashIndex; 1436997354e4b4a9666cedd62282471e97822affced9Mike Lockwood } 1437ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood return isNoMediaFile(path); 1438997354e4b4a9666cedd62282471e97822affced9Mike Lockwood } 1439997354e4b4a9666cedd62282471e97822affced9Mike Lockwood 1440c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood public void scanMtpFile(String path, String volumeName, int objectHandle, int format) { 14417a0bd17bceaf3efc3732e30c538fae420d3b742cMike Lockwood initialize(volumeName); 1442c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood MediaFile.MediaFileType mediaFileType = MediaFile.getFileType(path); 1443c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood int fileType = (mediaFileType == null ? 0 : mediaFileType.fileType); 14447a0bd17bceaf3efc3732e30c538fae420d3b742cMike Lockwood File file = new File(path); 14457a0bd17bceaf3efc3732e30c538fae420d3b742cMike Lockwood long lastModifiedSeconds = file.lastModified() / 1000; 1446c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood 1447c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood if (!MediaFile.isAudioFileType(fileType) && !MediaFile.isVideoFileType(fileType) && 144820c38ea9fd4024cc076c825f46cdfb34ffc090deJan Bjernler !MediaFile.isImageFileType(fileType) && !MediaFile.isPlayListFileType(fileType) && 144920c38ea9fd4024cc076c825f46cdfb34ffc090deJan Bjernler !MediaFile.isDrmFileType(fileType)) { 14507a0bd17bceaf3efc3732e30c538fae420d3b742cMike Lockwood 14517a0bd17bceaf3efc3732e30c538fae420d3b742cMike Lockwood // no need to use the media scanner, but we need to update last modified and file size 14527a0bd17bceaf3efc3732e30c538fae420d3b742cMike Lockwood ContentValues values = new ContentValues(); 14537a0bd17bceaf3efc3732e30c538fae420d3b742cMike Lockwood values.put(Files.FileColumns.SIZE, file.length()); 14547a0bd17bceaf3efc3732e30c538fae420d3b742cMike Lockwood values.put(Files.FileColumns.DATE_MODIFIED, lastModifiedSeconds); 14557a0bd17bceaf3efc3732e30c538fae420d3b742cMike Lockwood try { 14567a0bd17bceaf3efc3732e30c538fae420d3b742cMike Lockwood String[] whereArgs = new String[] { Integer.toString(objectHandle) }; 145735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn mMediaProvider.update(mPackageName, Files.getMtpObjectsUri(volumeName), values, 145835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn "_id=?", whereArgs); 14597a0bd17bceaf3efc3732e30c538fae420d3b742cMike Lockwood } catch (RemoteException e) { 14607a0bd17bceaf3efc3732e30c538fae420d3b742cMike Lockwood Log.e(TAG, "RemoteException in scanMtpFile", e); 14617a0bd17bceaf3efc3732e30c538fae420d3b742cMike Lockwood } 1462c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood return; 1463c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood } 1464c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood 1465d815f79766984fce499e147ecbacc01914683f74Mike Lockwood mMtpObjectHandle = objectHandle; 1466c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen Cursor fileList = null; 1467c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood try { 1468caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood if (MediaFile.isPlayListFileType(fileType)) { 1469caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood // build file cache so we can look up tracks in the playlist 1470caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood prescan(null, true); 1471caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood 147258ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen FileEntry entry = makeEntryFor(path); 1473caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood if (entry != null) { 147435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn fileList = mMediaProvider.query(mPackageName, mFilesUri, 147535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn FILES_PRESCAN_PROJECTION, null, null, null, null); 1476c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen processPlayList(entry, fileList); 1477caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood } 1478caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood } else { 1479caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood // MTP will create a file entry for us so we don't want to do it in prescan 1480caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood prescan(path, false); 1481c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood 1482caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood // always scan the file, so we can return the content://media Uri for existing files 1483076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood mClient.doScanFile(path, mediaFileType.mimeType, lastModifiedSeconds, file.length(), 1484997354e4b4a9666cedd62282471e97822affced9Mike Lockwood (format == MtpConstants.FORMAT_ASSOCIATION), true, isNoMediaPath(path)); 1485caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood } 1486c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood } catch (RemoteException e) { 1487c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood Log.e(TAG, "RemoteException in MediaScanner.scanFile()", e); 1488c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood } finally { 1489c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood mMtpObjectHandle = 0; 1490c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen if (fileList != null) { 1491c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen fileList.close(); 1492c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen } 14931b37c3bddcdfe7cb60e776e3eb05bfbb46b0b282Mattias Nilsson releaseResources(); 1494c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood } 1495d815f79766984fce499e147ecbacc01914683f74Mike Lockwood } 1496d815f79766984fce499e147ecbacc01914683f74Mike Lockwood 149758ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen FileEntry makeEntryFor(String path) { 149858ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen String where; 149958ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen String[] selectionArgs; 150058ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen 150158ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen Cursor c = null; 150258ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen try { 1503da8fe0faf5b52ef65bd07b6f47479ac537d42d47Marco Nelissen where = Files.FileColumns.DATA + "=?"; 1504da8fe0faf5b52ef65bd07b6f47479ac537d42d47Marco Nelissen selectionArgs = new String[] { path }; 150535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn c = mMediaProvider.query(mPackageName, mFilesUriNoNotify, FILES_PRESCAN_PROJECTION, 150658ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen where, selectionArgs, null, null); 15078ab2dc2f9680307febe997631c2148729f714e3dMarco Nelissen if (c.moveToFirst()) { 150858ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen long rowId = c.getLong(FILES_PRESCAN_ID_COLUMN_INDEX); 150958ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen int format = c.getInt(FILES_PRESCAN_FORMAT_COLUMN_INDEX); 151058ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen long lastModified = c.getLong(FILES_PRESCAN_DATE_MODIFIED_COLUMN_INDEX); 151158ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen return new FileEntry(rowId, path, lastModified, format); 151258ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen } 151358ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen } catch (RemoteException e) { 151458ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen } finally { 151558ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen if (c != null) { 151658ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen c.close(); 151758ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen } 151858ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen } 151958ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen return null; 152058ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen } 152158ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen 15229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // returns the number of matching file/directory names, starting from the right 15239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int matchPaths(String path1, String path2) { 15249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int result = 0; 15259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int end1 = path1.length(); 15269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int end2 = path2.length(); 152720b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 15289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (end1 > 0 && end2 > 0) { 15299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int slash1 = path1.lastIndexOf('/', end1 - 1); 15309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int slash2 = path2.lastIndexOf('/', end2 - 1); 15319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int backSlash1 = path1.lastIndexOf('\\', end1 - 1); 15329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int backSlash2 = path2.lastIndexOf('\\', end2 - 1); 15339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int start1 = (slash1 > backSlash1 ? slash1 : backSlash1); 15349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int start2 = (slash2 > backSlash2 ? slash2 : backSlash2); 15359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (start1 < 0) start1 = 0; else start1++; 15369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (start2 < 0) start2 = 0; else start2++; 15379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int length = end1 - start1; 15389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (end2 - start2 != length) break; 15399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (path1.regionMatches(true, start1, path2, start2, length)) { 15409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project result++; 15419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project end1 = start1 - 1; 15429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project end2 = start2 - 1; 15439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else break; 15449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 154520b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 15469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return result; 15479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15490b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen private boolean matchEntries(long rowId, String data) { 15500b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen 15510b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen int len = mPlaylistEntries.size(); 15520b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen boolean done = true; 15530b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen for (int i = 0; i < len; i++) { 15540b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen PlaylistEntry entry = mPlaylistEntries.get(i); 15550b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen if (entry.bestmatchlevel == Integer.MAX_VALUE) { 15560b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen continue; // this entry has been matched already 15570b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen } 15580b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen done = false; 15590b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen if (data.equalsIgnoreCase(entry.path)) { 15600b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen entry.bestmatchid = rowId; 15610b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen entry.bestmatchlevel = Integer.MAX_VALUE; 15620b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen continue; // no need for path matching 15630b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen } 15640b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen 15650b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen int matchLength = matchPaths(data, entry.path); 15660b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen if (matchLength > entry.bestmatchlevel) { 15670b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen entry.bestmatchid = rowId; 15680b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen entry.bestmatchlevel = matchLength; 15690b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen } 15700b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen } 15710b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen return done; 15720b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen } 157320b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 15740b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen private void cachePlaylistEntry(String line, String playListDirectory) { 15750b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen PlaylistEntry entry = new PlaylistEntry(); 15769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // watch for trailing whitespace 15770b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen int entryLength = line.length(); 15780b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen while (entryLength > 0 && Character.isWhitespace(line.charAt(entryLength - 1))) entryLength--; 15799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // path should be longer than 3 characters. 15809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // avoid index out of bounds errors below by returning here. 15810b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen if (entryLength < 3) return; 15820b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen if (entryLength < line.length()) line = line.substring(0, entryLength); 15839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // does entry appear to be an absolute path? 15859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // look for Unix or DOS absolute paths 15860b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen char ch1 = line.charAt(0); 15879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean fullPath = (ch1 == '/' || 15880b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen (Character.isLetter(ch1) && line.charAt(1) == ':' && line.charAt(2) == '\\')); 15899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // if we have a relative path, combine entry with playListDirectory 15909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!fullPath) 15910b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen line = playListDirectory + line; 15920b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen entry.path = line; 15939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //FIXME - should we look for "../" within the path? 159420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 15950b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen mPlaylistEntries.add(entry); 15960b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen } 159720b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 15980b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen private void processCachedPlaylist(Cursor fileList, ContentValues values, Uri playlistUri) { 15990b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen fileList.moveToPosition(-1); 16000b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen while (fileList.moveToNext()) { 16010b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen long rowId = fileList.getLong(FILES_PRESCAN_ID_COLUMN_INDEX); 16020b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen String data = fileList.getString(FILES_PRESCAN_PATH_COLUMN_INDEX); 16030b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen if (matchEntries(rowId, data)) { 16040b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen break; 16059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 160720b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 16080b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen int len = mPlaylistEntries.size(); 16090b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen int index = 0; 16100b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen for (int i = 0; i < len; i++) { 16110b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen PlaylistEntry entry = mPlaylistEntries.get(i); 16120b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen if (entry.bestmatchlevel > 0) { 16130b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen try { 16140b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen values.clear(); 16150b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen values.put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, Integer.valueOf(index)); 16160b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen values.put(MediaStore.Audio.Playlists.Members.AUDIO_ID, Long.valueOf(entry.bestmatchid)); 161735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn mMediaProvider.insert(mPackageName, playlistUri, values); 16180b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen index++; 16190b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen } catch (RemoteException e) { 16200b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen Log.e(TAG, "RemoteException in MediaScanner.processCachedPlaylist()", e); 16210b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen return; 16227d92a22d9dec42a45cd55fd77d0a86b4b9c6e9dfDongwon Kang } 16237d92a22d9dec42a45cd55fd77d0a86b4b9c6e9dfDongwon Kang } 16249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16250b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen mPlaylistEntries.clear(); 16269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 162720b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 1628c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen private void processM3uPlayList(String path, String playListDirectory, Uri uri, 1629c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen ContentValues values, Cursor fileList) { 16309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project BufferedReader reader = null; 16319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 16329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project File f = new File(path); 16339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (f.exists()) { 16349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project reader = new BufferedReader( 16359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project new InputStreamReader(new FileInputStream(f)), 8192); 16369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String line = reader.readLine(); 16370b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen mPlaylistEntries.clear(); 16389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (line != null) { 16399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // ignore comment lines, which begin with '#' 16409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (line.length() > 0 && line.charAt(0) != '#') { 16410b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen cachePlaylistEntry(line, playListDirectory); 16429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project line = reader.readLine(); 16449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16450b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen 16460b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen processCachedPlaylist(fileList, values, uri); 16479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 16499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "IOException in MediaScanner.processM3uPlayList()", e); 16509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 16519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 16529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (reader != null) 16539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project reader.close(); 16549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 16559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "IOException in MediaScanner.processM3uPlayList()", e); 16569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1660c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen private void processPlsPlayList(String path, String playListDirectory, Uri uri, 1661c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen ContentValues values, Cursor fileList) { 16629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project BufferedReader reader = null; 16639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 16649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project File f = new File(path); 16659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (f.exists()) { 16669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project reader = new BufferedReader( 16679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project new InputStreamReader(new FileInputStream(f)), 8192); 16689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String line = reader.readLine(); 16690b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen mPlaylistEntries.clear(); 16709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (line != null) { 16719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // ignore comment lines, which begin with '#' 16729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (line.startsWith("File")) { 16739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int equals = line.indexOf('='); 16749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (equals > 0) { 1675538d4925b36067dc89ad0625a69dafeaa364bd2eMarco Nelissen cachePlaylistEntry(line.substring(equals + 1), playListDirectory); 16769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project line = reader.readLine(); 16799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16800b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen 16810b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen processCachedPlaylist(fileList, values, uri); 16829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 16849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "IOException in MediaScanner.processPlsPlayList()", e); 16859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 16869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 16879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (reader != null) 16889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project reader.close(); 16899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 16909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "IOException in MediaScanner.processPlsPlayList()", e); 16919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project class WplHandler implements ElementListener { 16969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final ContentHandler handler; 16989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String playListDirectory; 16999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1700c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen public WplHandler(String playListDirectory, Uri uri, Cursor fileList) { 17019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this.playListDirectory = playListDirectory; 170220b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 17039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project RootElement root = new RootElement("smil"); 17049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Element body = root.getChild("body"); 17059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Element seq = body.getChild("seq"); 17069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Element media = seq.getChild("media"); 17079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project media.setElementListener(this); 17089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this.handler = root.getContentHandler(); 17109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1712c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen @Override 17139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void start(Attributes attributes) { 17149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String path = attributes.getValue("", "src"); 17159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (path != null) { 17160b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen cachePlaylistEntry(path, playListDirectory); 17179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17200b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen @Override 17219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void end() { 17229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ContentHandler getContentHandler() { 17259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return handler; 17269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1729c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen private void processWplPlayList(String path, String playListDirectory, Uri uri, 17300b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen ContentValues values, Cursor fileList) { 17319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project FileInputStream fis = null; 17329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 17339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project File f = new File(path); 17349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (f.exists()) { 17359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fis = new FileInputStream(f); 17369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17370b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen mPlaylistEntries.clear(); 1738c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen Xml.parse(fis, Xml.findEncodingByName("UTF-8"), 1739c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen new WplHandler(playListDirectory, uri, fileList).getContentHandler()); 17400b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen 17410b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen processCachedPlaylist(fileList, values, uri); 17429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (SAXException e) { 17449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project e.printStackTrace(); 17459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 17469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project e.printStackTrace(); 17479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 17489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 17499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (fis != null) 17509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fis.close(); 17519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 17529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "IOException in MediaScanner.processWplPlayList()", e); 17539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 175620b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 1757c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen private void processPlayList(FileEntry entry, Cursor fileList) throws RemoteException { 1758caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood String path = entry.mPath; 1759caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood ContentValues values = new ContentValues(); 1760caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood int lastSlash = path.lastIndexOf('/'); 1761caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood if (lastSlash < 0) throw new IllegalArgumentException("bad path " + path); 1762caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood Uri uri, membersUri; 1763caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood long rowId = entry.mRowId; 1764caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood 1765242d0cdc1ad6c48faca403ea352bde73138443b5Mike Lockwood // make sure we have a name 1766242d0cdc1ad6c48faca403ea352bde73138443b5Mike Lockwood String name = values.getAsString(MediaStore.Audio.Playlists.NAME); 1767242d0cdc1ad6c48faca403ea352bde73138443b5Mike Lockwood if (name == null) { 1768242d0cdc1ad6c48faca403ea352bde73138443b5Mike Lockwood name = values.getAsString(MediaStore.MediaColumns.TITLE); 1769242d0cdc1ad6c48faca403ea352bde73138443b5Mike Lockwood if (name == null) { 1770242d0cdc1ad6c48faca403ea352bde73138443b5Mike Lockwood // extract name from file name 1771242d0cdc1ad6c48faca403ea352bde73138443b5Mike Lockwood int lastDot = path.lastIndexOf('.'); 1772242d0cdc1ad6c48faca403ea352bde73138443b5Mike Lockwood name = (lastDot < 0 ? path.substring(lastSlash + 1) 1773242d0cdc1ad6c48faca403ea352bde73138443b5Mike Lockwood : path.substring(lastSlash + 1, lastDot)); 1774242d0cdc1ad6c48faca403ea352bde73138443b5Mike Lockwood } 1775242d0cdc1ad6c48faca403ea352bde73138443b5Mike Lockwood } 1776242d0cdc1ad6c48faca403ea352bde73138443b5Mike Lockwood 1777242d0cdc1ad6c48faca403ea352bde73138443b5Mike Lockwood values.put(MediaStore.Audio.Playlists.NAME, name); 1778242d0cdc1ad6c48faca403ea352bde73138443b5Mike Lockwood values.put(MediaStore.Audio.Playlists.DATE_MODIFIED, entry.mLastModified); 1779242d0cdc1ad6c48faca403ea352bde73138443b5Mike Lockwood 1780242d0cdc1ad6c48faca403ea352bde73138443b5Mike Lockwood if (rowId == 0) { 1781caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood values.put(MediaStore.Audio.Playlists.DATA, path); 178235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn uri = mMediaProvider.insert(mPackageName, mPlaylistsUri, values); 1783caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood rowId = ContentUris.parseId(uri); 1784caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood membersUri = Uri.withAppendedPath(uri, Playlists.Members.CONTENT_DIRECTORY); 1785caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood } else { 1786caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood uri = ContentUris.withAppendedId(mPlaylistsUri, rowId); 178735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn mMediaProvider.update(mPackageName, uri, values, null, null); 178820b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 1789caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood // delete members of existing playlist 1790caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood membersUri = Uri.withAppendedPath(uri, Playlists.Members.CONTENT_DIRECTORY); 179135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn mMediaProvider.delete(mPackageName, membersUri, null, null); 1792caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood } 17939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1794caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood String playListDirectory = path.substring(0, lastSlash + 1); 1795caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood MediaFile.MediaFileType mediaFileType = MediaFile.getFileType(path); 1796caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood int fileType = (mediaFileType == null ? 0 : mediaFileType.fileType); 179720b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 1798caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood if (fileType == MediaFile.FILE_TYPE_M3U) { 1799c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen processM3uPlayList(path, playListDirectory, membersUri, values, fileList); 1800caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood } else if (fileType == MediaFile.FILE_TYPE_PLS) { 1801c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen processPlsPlayList(path, playListDirectory, membersUri, values, fileList); 1802caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood } else if (fileType == MediaFile.FILE_TYPE_WPL) { 18030b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen processWplPlayList(path, playListDirectory, membersUri, values, fileList); 1804caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood } 1805caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood } 180620b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 1807caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood private void processPlayLists() throws RemoteException { 180858ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen Iterator<FileEntry> iterator = mPlayLists.iterator(); 1809c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen Cursor fileList = null; 1810c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen try { 181108f70fa5b82faa00d4d536b5a220d7ce8dd8f932Marco Nelissen // use the files uri and projection because we need the format column, 181208f70fa5b82faa00d4d536b5a220d7ce8dd8f932Marco Nelissen // but restrict the query to just audio files 181335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn fileList = mMediaProvider.query(mPackageName, mFilesUri, FILES_PRESCAN_PROJECTION, 181408f70fa5b82faa00d4d536b5a220d7ce8dd8f932Marco Nelissen "media_type=2", null, null, null); 1815c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen while (iterator.hasNext()) { 1816c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen FileEntry entry = iterator.next(); 1817c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen // only process playlist files if they are new or have been modified since the last scan 1818c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen if (entry.mLastModifiedChanged) { 1819c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen processPlayList(entry, fileList); 1820c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen } 1821c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen } 1822c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen } catch (RemoteException e1) { 1823c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen } finally { 1824c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen if (fileList != null) { 1825c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen fileList.close(); 18269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 182920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 1830c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood private native void processDirectory(String path, MediaScannerClient client); 18319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private native void processFile(String path, String mimeType, MediaScannerClient client); 18329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public native void setLocale(String locale); 183320b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 18349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public native byte[] extractAlbumArt(FileDescriptor fd); 18359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18364935d05eaa306cef88cf0ab13eca386f270409ecMarco Nelissen private static native final void native_init(); 18379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private native final void native_setup(); 18389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private native final void native_finalize(); 1839133cf8b92a07d5be8c64607b9644aa9cef169fb0James Dong 1840133cf8b92a07d5be8c64607b9644aa9cef169fb0James Dong /** 18410b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen * Releases resources associated with this MediaScanner object. 1842133cf8b92a07d5be8c64607b9644aa9cef169fb0James Dong * It is considered good practice to call this method when 1843133cf8b92a07d5be8c64607b9644aa9cef169fb0James Dong * one is done using the MediaScanner object. After this method 1844133cf8b92a07d5be8c64607b9644aa9cef169fb0James Dong * is called, the MediaScanner object can no longer be used. 1845133cf8b92a07d5be8c64607b9644aa9cef169fb0James Dong */ 1846133cf8b92a07d5be8c64607b9644aa9cef169fb0James Dong public void release() { 1847133cf8b92a07d5be8c64607b9644aa9cef169fb0James Dong native_finalize(); 1848133cf8b92a07d5be8c64607b9644aa9cef169fb0James Dong } 1849133cf8b92a07d5be8c64607b9644aa9cef169fb0James Dong 18509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 185120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync protected void finalize() { 18529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.getContentResolver().releaseProvider(mMediaProvider); 185320b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync native_finalize(); 18549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1856