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 1960cfad80bdf61db436643927337c2fb30186e99dJeff Sharkeyimport android.content.ContentProviderClient; 2068528911b9f74475ac79c369a6482f720259dbacMarco Nelissenimport android.content.ContentResolver; 21bfcb22a207499c7ecd4aef9bea2ac778d8be8fc8Marco Nelissenimport android.content.ContentUris; 229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ContentValues; 239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context; 2417d24400906235a172fc760e98656589692f798aJean-Michel Triviimport android.content.SharedPreferences; 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.database.Cursor; 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.database.SQLException; 275d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wangimport android.drm.DrmManagerClient; 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.BitmapFactory; 290cd0136d440cf6ad9d5fab430269116786e671ecMike Lockwoodimport android.mtp.MtpConstants; 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.Uri; 3117d24400906235a172fc760e98656589692f798aJean-Michel Triviimport android.os.Build; 32250528e5b2362cb7b6749afb331acd8226f67744Mike Lockwoodimport android.os.Environment; 339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.RemoteException; 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemProperties; 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.MediaStore; 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.MediaStore.Audio; 370b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissenimport android.provider.MediaStore.Audio.Playlists; 38c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwoodimport android.provider.MediaStore.Files; 390b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissenimport android.provider.MediaStore.Files.FileColumns; 409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.MediaStore.Images; 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.MediaStore.Video; 420b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissenimport android.provider.Settings; 4368528911b9f74475ac79c369a6482f720259dbacMarco Nelissenimport android.provider.Settings.SettingNotFoundException; 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 5360cfad80bdf61db436643927337c2fb30186e99dJeff Sharkeyimport dalvik.system.CloseGuard; 5460cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey 5560cfad80bdf61db436643927337c2fb30186e99dJeff Sharkeyimport org.xml.sax.Attributes; 5660cfad80bdf61db436643927337c2fb30186e99dJeff Sharkeyimport org.xml.sax.ContentHandler; 5760cfad80bdf61db436643927337c2fb30186e99dJeff Sharkeyimport org.xml.sax.SAXException; 5860cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey 59bfcb22a207499c7ecd4aef9bea2ac778d8be8fc8Marco Nelissenimport java.io.BufferedReader; 60bfcb22a207499c7ecd4aef9bea2ac778d8be8fc8Marco Nelissenimport java.io.File; 61bfcb22a207499c7ecd4aef9bea2ac778d8be8fc8Marco Nelissenimport java.io.FileDescriptor; 62bfcb22a207499c7ecd4aef9bea2ac778d8be8fc8Marco Nelissenimport java.io.FileInputStream; 63bfcb22a207499c7ecd4aef9bea2ac778d8be8fc8Marco Nelissenimport java.io.IOException; 64bfcb22a207499c7ecd4aef9bea2ac778d8be8fc8Marco Nelissenimport java.io.InputStreamReader; 655f0c3a531938c0c1399efab94906aee74eff9108Bryan Mawhinneyimport java.text.SimpleDateFormat; 665f0c3a531938c0c1399efab94906aee74eff9108Bryan Mawhinneyimport java.text.ParseException; 679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList; 6893a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissenimport java.util.HashMap; 699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.HashSet; 709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Iterator; 71ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissenimport java.util.Locale; 725f0c3a531938c0c1399efab94906aee74eff9108Bryan Mawhinneyimport java.util.TimeZone; 7360cfad80bdf61db436643927337c2fb30186e99dJeff Sharkeyimport java.util.concurrent.atomic.AtomicBoolean; 749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 7677f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * Internal service helper that no-one should use directly. 7720b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync * 7877f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * The way the scan currently works is: 7977f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * - The Java MediaScannerService creates a MediaScanner (this class), and calls 8077f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * MediaScanner.scanDirectories on it. 8177f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * - scanDirectories() calls the native processDirectory() for each of the specified directories. 8277f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * - the processDirectory() JNI method wraps the provided mediascanner client in a native 8377f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * 'MyMediaScannerClient' class, then calls processDirectory() on the native MediaScanner 8477f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * object (which got created when the Java MediaScanner was created). 857ae82ce1fd54103bb87b8a0593a4228c94b1d6f9James Dong * - native MediaScanner.processDirectory() calls 8677f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * doProcessDirectory(), which recurses over the folder, and calls 8777f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * native MyMediaScannerClient.scanFile() for every file whose extension matches. 8877f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * - native MyMediaScannerClient.scanFile() calls back on Java MediaScannerClient.scanFile, 8977f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * which calls doScanFile, which after some setup calls back down to native code, calling 9077f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * MediaScanner.processFile(). 9177f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * - MediaScanner.processFile() calls one of several methods, depending on the type of the 9277f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * file: parseMP3, parseMP4, parseMidi, parseOgg or parseWMA. 9377f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * - each of these methods gets metadata key/value pairs from the file, and repeatedly 9477f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * calls native MyMediaScannerClient.handleStringTag, which calls back up to its Java 9577f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * counterparts in this file. 9677f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * - Java handleStringTag() gathers the key/value pairs that it's interested in. 9777f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * - once processFile returns and we're back in Java code in doScanFile(), it calls 9877f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * Java MyMediaScannerClient.endFile(), which takes all the data that's been 9977f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * gathered and inserts an entry in to the database. 10077f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * 10177f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * In summary: 10277f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * Java MediaScannerService calls 10377f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * Java MediaScanner scanDirectories, which calls 10477f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * Java MediaScanner processDirectory (native method), which calls 10577f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * native MediaScanner processDirectory, which calls 10677f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * native MyMediaScannerClient scanFile, which calls 10777f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * Java MyMediaScannerClient scanFile, which calls 10877f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * Java MediaScannerClient doScanFile, which calls 10977f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * Java MediaScanner processFile (native method), which calls 11077f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * native MediaScanner processFile, which calls 11177f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * native parseMP3, parseMP4, parseMidi, parseOgg or parseWMA, which calls 11277f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * native MyMediaScanner handleStringTag, which calls 11377f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * Java MyMediaScanner handleStringTag. 11477f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * Once MediaScanner processFile returns, an entry is inserted in to the database. 1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 116af16d0b30e89f31b7617424c8706553ff571d08dMike Lockwood * The MediaScanner class is not thread-safe, so it should only be used in a single threaded manner. 117af16d0b30e89f31b7617424c8706553ff571d08dMike Lockwood * 1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@hide} 1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 12060cfad80bdf61db436643927337c2fb30186e99dJeff Sharkeypublic class MediaScanner implements AutoCloseable { 1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static { 1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project System.loadLibrary("media_jni"); 1234935d05eaa306cef88cf0ab13eca386f270409ecMarco Nelissen native_init(); 1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final static String TAG = "MediaScanner"; 1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 128d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood private static final String[] FILES_PRESCAN_PROJECTION = new String[] { 129c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood Files.FileColumns._ID, // 0 130c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood Files.FileColumns.DATA, // 1 131d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood Files.FileColumns.FORMAT, // 2 132d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood Files.FileColumns.DATE_MODIFIED, // 3 1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 13420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 1356458935331ccfacb4cccc50d6b893947febae687Mike Lockwood private static final String[] ID_PROJECTION = new String[] { 1366458935331ccfacb4cccc50d6b893947febae687Mike Lockwood Files.FileColumns._ID, 1376458935331ccfacb4cccc50d6b893947febae687Mike Lockwood }; 1386458935331ccfacb4cccc50d6b893947febae687Mike Lockwood 139d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood private static final int FILES_PRESCAN_ID_COLUMN_INDEX = 0; 140d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood private static final int FILES_PRESCAN_PATH_COLUMN_INDEX = 1; 141d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood private static final int FILES_PRESCAN_FORMAT_COLUMN_INDEX = 2; 142d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood private static final int FILES_PRESCAN_DATE_MODIFIED_COLUMN_INDEX = 3; 143d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood 1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String[] PLAYLIST_MEMBERS_PROJECTION = new String[] { 1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Audio.Playlists.Members.PLAYLIST_ID, // 0 1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int ID_PLAYLISTS_COLUMN_INDEX = 0; 1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int PATH_PLAYLISTS_COLUMN_INDEX = 1; 1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int DATE_MODIFIED_PLAYLISTS_COLUMN_INDEX = 2; 1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String RINGTONES_DIR = "/ringtones/"; 1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String NOTIFICATIONS_DIR = "/notifications/"; 1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String ALARMS_DIR = "/alarms/"; 1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String MUSIC_DIR = "/music/"; 1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String PODCAST_DIR = "/podcasts/"; 15720b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 15817d24400906235a172fc760e98656589692f798aJean-Michel Trivi public static final String SCANNED_BUILD_PREFS_NAME = "MediaScanBuild"; 15917d24400906235a172fc760e98656589692f798aJean-Michel Trivi public static final String LAST_INTERNAL_SCAN_FINGERPRINT = "lastScanFingerprint"; 16017d24400906235a172fc760e98656589692f798aJean-Michel Trivi private static final String SYSTEM_SOUNDS_DIR = "/system/media/audio"; 161c31033f43c85a07ebc6045c9b5af5408d0b306e9Jaekyun Seok private static final String PRODUCT_SOUNDS_DIR = "/product/media/audio"; 16217d24400906235a172fc760e98656589692f798aJean-Michel Trivi private static String sLastInternalScanFingerprint; 16317d24400906235a172fc760e98656589692f798aJean-Michel Trivi 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String[] ID3_GENRES = { 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // ID3v1 Genres 1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Blues", 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Classic Rock", 1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Country", 1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Dance", 1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Disco", 1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Funk", 1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Grunge", 1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Hip-Hop", 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Jazz", 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Metal", 1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "New Age", 1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Oldies", 1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Other", 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Pop", 1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "R&B", 1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Rap", 1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Reggae", 1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Rock", 1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Techno", 1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Industrial", 1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Alternative", 1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Ska", 1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Death Metal", 1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Pranks", 1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Soundtrack", 1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Euro-Techno", 1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Ambient", 1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Trip-Hop", 1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Vocal", 1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Jazz+Funk", 1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Fusion", 1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Trance", 1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Classical", 1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Instrumental", 2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Acid", 2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "House", 2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Game", 2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Sound Clip", 2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Gospel", 2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Noise", 2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "AlternRock", 2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Bass", 2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Soul", 2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Punk", 2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Space", 2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Meditative", 2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Instrumental Pop", 2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Instrumental Rock", 2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Ethnic", 2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Gothic", 2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Darkwave", 2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Techno-Industrial", 2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Electronic", 2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Pop-Folk", 2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Eurodance", 2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Dream", 2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Southern Rock", 2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Comedy", 2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Cult", 2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Gangsta", 2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Top 40", 2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Christian Rap", 2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Pop/Funk", 2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Jungle", 2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Native American", 2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Cabaret", 2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "New Wave", 2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Psychadelic", 2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Rave", 2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Showtunes", 2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Trailer", 2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Lo-Fi", 2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Tribal", 2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Acid Punk", 2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Acid Jazz", 2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Polka", 2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Retro", 2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Musical", 2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Rock & Roll", 2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Hard Rock", 2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // The following genres are Winamp extensions 2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Folk", 2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Folk-Rock", 2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "National Folk", 2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Swing", 2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Fast Fusion", 2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Bebob", 2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Latin", 2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Revival", 2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Celtic", 2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Bluegrass", 2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Avantgarde", 2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Gothic Rock", 2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Progressive Rock", 2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Psychedelic Rock", 2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Symphonic Rock", 2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Slow Rock", 2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Big Band", 2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Chorus", 2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Easy Listening", 2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Acoustic", 2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Humour", 2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Speech", 2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Chanson", 2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Opera", 2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Chamber Music", 2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Sonata", 2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Symphony", 2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Booty Bass", 2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Primus", 2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Porn Groove", 2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Satire", 2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Slow Jam", 2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Club", 2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Tango", 2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Samba", 2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Folklore", 2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Ballad", 2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Power Ballad", 2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Rhythmic Soul", 2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Freestyle", 2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Duet", 2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Punk Rock", 2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Drum Solo", 2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "A capella", 2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Euro-House", 292cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen "Dance Hall", 293cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen // The following ones seem to be fairly widely supported as well 294cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen "Goa", 295cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen "Drum & Bass", 296cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen "Club-House", 297cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen "Hardcore", 298cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen "Terror", 299cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen "Indie", 300cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen "Britpop", 301c3ea477e2111f199d10341b121791cb2ec91eca3Johan Redestig null, 302cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen "Polsk Punk", 303cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen "Beat", 304cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen "Christian Gangsta", 305cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen "Heavy Metal", 306cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen "Black Metal", 307cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen "Crossover", 308cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen "Contemporary Christian", 309cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen "Christian Rock", 310cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen "Merengue", 311cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen "Salsa", 312cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen "Thrash Metal", 313cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen "Anime", 314cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen "JPop", 315cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen "Synthpop", 316cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen // 148 and up don't seem to have been defined yet. 3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 319075e9a19ce645752f8282bc19c91b25978a7dc52Ashok Bhat private long mNativeContext; 32060cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey private final Context mContext; 32160cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey private final String mPackageName; 32260cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey private final String mVolumeName; 32360cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey private final ContentProviderClient mMediaProvider; 32460cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey private final Uri mAudioUri; 32560cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey private final Uri mVideoUri; 32660cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey private final Uri mImagesUri; 32760cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey private final Uri mPlaylistsUri; 32860cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey private final Uri mFilesUri; 32960cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey private final Uri mFilesUriNoNotify; 33060cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey private final boolean mProcessPlaylists; 33160cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey private final boolean mProcessGenres; 332d815f79766984fce499e147ecbacc01914683f74Mike Lockwood private int mMtpObjectHandle; 3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 33460cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey private final AtomicBoolean mClosed = new AtomicBoolean(); 33560cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey private final CloseGuard mCloseGuard = CloseGuard.get(); 336250528e5b2362cb7b6749afb331acd8226f67744Mike Lockwood 337d6b3e0cc36cbe28c8d194b63227df37c76af7efaMarco Nelissen /** whether to use bulk inserts or individual inserts for each item */ 338d6b3e0cc36cbe28c8d194b63227df37c76af7efaMarco Nelissen private static final boolean ENABLE_BULK_INSERTS = true; 3393410b4656505673c72da558dcfec94d7b135e760Mike Lockwood 3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // used when scanning the image database so we know whether we have to prune 3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // old thumbnail files 3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mOriginalCount; 3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** Whether the scanner has set a default sound for the ringer ringtone. */ 3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mDefaultRingtoneSet; 3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** Whether the scanner has set a default sound for the notification ringtone. */ 3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mDefaultNotificationSet; 3473156bb00dd3ab3d6ec732bb6a64a2e84d08c34f0Patrick Scott /** Whether the scanner has set a default sound for the alarm ringtone. */ 3483156bb00dd3ab3d6ec732bb6a64a2e84d08c34f0Patrick Scott private boolean mDefaultAlarmSet; 3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** The filename for the default sound for the ringer ringtone. */ 3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String mDefaultRingtoneFilename; 3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** The filename for the default sound for the notification ringtone. */ 3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String mDefaultNotificationFilename; 3533156bb00dd3ab3d6ec732bb6a64a2e84d08c34f0Patrick Scott /** The filename for the default sound for the alarm ringtone. */ 3543156bb00dd3ab3d6ec732bb6a64a2e84d08c34f0Patrick Scott private String mDefaultAlarmAlertFilename; 3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The prefix for system properties that define the default sound for 3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * ringtones. Concatenate the name of the setting from Settings 3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * to get the full system property. 3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String DEFAULT_RINGTONE_PROPERTY_PREFIX = "ro.config."; 36120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 36230c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten private final BitmapFactory.Options mBitmapOptions = new BitmapFactory.Options(); 3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 36458ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen private static class FileEntry { 3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long mRowId; 3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String mPath; 3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long mLastModified; 368d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood int mFormat; 3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean mLastModifiedChanged; 37020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 37158ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen FileEntry(long rowId, String path, long lastModified, int format) { 3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mRowId = rowId; 3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPath = path; 3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLastModified = lastModified; 375d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood mFormat = format; 3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLastModifiedChanged = false; 3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String toString() { 3813e5e8055942ee8179675b8ed11d40ca12dbe42e6Marco Nelissen return mPath + " mRowId: " + mRowId; 3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 38420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 3850b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen private static class PlaylistEntry { 3860b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen String path; 3870b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen long bestmatchid; 3880b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen int bestmatchlevel; 3890b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen } 3900b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen 39160cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey private final ArrayList<PlaylistEntry> mPlaylistEntries = new ArrayList<>(); 39260cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey private final ArrayList<FileEntry> mPlayLists = new ArrayList<>(); 3930b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen 3948e2ed8d512ade2ea481b3a292556782b17a74674Dongwon Kang private MediaInserter mMediaInserter; 395bd682b040833fce9e212c00c395b32bec7050f87Mike Lockwood 3965d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang private DrmManagerClient mDrmManagerClient = null; 3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 39860cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey public MediaScanner(Context c, String volumeName) { 3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project native_setup(); 4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext = c; 40135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn mPackageName = c.getPackageName(); 40260cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey mVolumeName = volumeName; 40360cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey 4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mBitmapOptions.inSampleSize = 1; 4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mBitmapOptions.inJustDecodeBounds = true; 40620b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setDefaultRingtoneFileNames(); 408250528e5b2362cb7b6749afb331acd8226f67744Mike Lockwood 40960cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey mMediaProvider = mContext.getContentResolver() 41060cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey .acquireContentProviderClient(MediaStore.AUTHORITY); 41160cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey 41217d24400906235a172fc760e98656589692f798aJean-Michel Trivi if (sLastInternalScanFingerprint == null) { 41317d24400906235a172fc760e98656589692f798aJean-Michel Trivi final SharedPreferences scanSettings = 41417d24400906235a172fc760e98656589692f798aJean-Michel Trivi mContext.getSharedPreferences(SCANNED_BUILD_PREFS_NAME, Context.MODE_PRIVATE); 41517d24400906235a172fc760e98656589692f798aJean-Michel Trivi sLastInternalScanFingerprint = 41617d24400906235a172fc760e98656589692f798aJean-Michel Trivi scanSettings.getString(LAST_INTERNAL_SCAN_FINGERPRINT, new String()); 41717d24400906235a172fc760e98656589692f798aJean-Michel Trivi } 41817d24400906235a172fc760e98656589692f798aJean-Michel Trivi 41960cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey mAudioUri = Audio.Media.getContentUri(volumeName); 42060cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey mVideoUri = Video.Media.getContentUri(volumeName); 42160cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey mImagesUri = Images.Media.getContentUri(volumeName); 42260cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey mFilesUri = Files.getContentUri(volumeName); 42360cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey mFilesUriNoNotify = mFilesUri.buildUpon().appendQueryParameter("nonotify", "1").build(); 42460cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey 42560cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey if (!volumeName.equals("internal")) { 42660cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey // we only support playlists on external media 42760cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey mProcessPlaylists = true; 42860cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey mProcessGenres = true; 42960cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey mPlaylistsUri = Playlists.getContentUri(volumeName); 43060cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey } else { 43160cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey mProcessPlaylists = false; 43260cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey mProcessGenres = false; 43360cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey mPlaylistsUri = null; 43460cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey } 43560cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey 43660cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey final Locale locale = mContext.getResources().getConfiguration().locale; 43760cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey if (locale != null) { 43860cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey String language = locale.getLanguage(); 43960cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey String country = locale.getCountry(); 44060cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey if (language != null) { 44160cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey if (country != null) { 44260cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey setLocale(language + "_" + country); 44360cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey } else { 44460cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey setLocale(language); 44560cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey } 44660cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey } 44760cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey } 44860cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey 44960cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey mCloseGuard.open("close"); 4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void setDefaultRingtoneFileNames() { 4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDefaultRingtoneFilename = SystemProperties.get(DEFAULT_RINGTONE_PROPERTY_PREFIX 4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + Settings.System.RINGTONE); 4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDefaultNotificationFilename = SystemProperties.get(DEFAULT_RINGTONE_PROPERTY_PREFIX 4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + Settings.System.NOTIFICATION_SOUND); 4573156bb00dd3ab3d6ec732bb6a64a2e84d08c34f0Patrick Scott mDefaultAlarmAlertFilename = SystemProperties.get(DEFAULT_RINGTONE_PROPERTY_PREFIX 4583156bb00dd3ab3d6ec732bb6a64a2e84d08c34f0Patrick Scott + Settings.System.ALARM_ALERT); 4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 46020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 46130c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten private final MyMediaScannerClient mClient = new MyMediaScannerClient(); 46220b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 463e4eb4d9de37a8e9ed6f43a5f7deccf88f28bfc8bMarco Nelissen private boolean isDrmEnabled() { 4641f89c4f9f8df5d7125221250993ba1e853ed9fedGloria Wang String prop = SystemProperties.get("drm.service.enabled"); 465e4eb4d9de37a8e9ed6f43a5f7deccf88f28bfc8bMarco Nelissen return prop != null && prop.equals("true"); 466e4eb4d9de37a8e9ed6f43a5f7deccf88f28bfc8bMarco Nelissen } 467fbc4939d2b51d511858846363bf02c7c9f851ed2Mike Lockwood 4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private class MyMediaScannerClient implements MediaScannerClient { 46920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 4705f0c3a531938c0c1399efab94906aee74eff9108Bryan Mawhinney private final SimpleDateFormat mDateFormatter; 4715f0c3a531938c0c1399efab94906aee74eff9108Bryan Mawhinney 4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String mArtist; 4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String mAlbumArtist; // use this if mArtist is missing 4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String mAlbum; 4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String mTitle; 4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String mComposer; 4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String mGenre; 4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String mMimeType; 4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mFileType; 4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mTrack; 4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mYear; 4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mDuration; 4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String mPath; 4845f0c3a531938c0c1399efab94906aee74eff9108Bryan Mawhinney private long mDate; 4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private long mLastModified; 4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private long mFileSize; 487c9706f0262a2f399f95e0d78ba2b7616e08d0069Sahil Sachdeva private String mWriter; 488f679ba7d944a403fbdc77926c44978ffd5161f2dMarco Nelissen private int mCompilation; 48982428a862f325238cfb5646bbd65de3f1a11e7ccGloria Wang private boolean mIsDrm; 490997354e4b4a9666cedd62282471e97822affced9Mike Lockwood private boolean mNoMedia; // flag to suppress file from appearing in media tables 491bab75909fac9c65b71012f4c06302503c2f72be1Marco Nelissen private boolean mScanSuccess; 492e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang private int mWidth; 493e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang private int mHeight; 49420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 4955f0c3a531938c0c1399efab94906aee74eff9108Bryan Mawhinney public MyMediaScannerClient() { 4965f0c3a531938c0c1399efab94906aee74eff9108Bryan Mawhinney mDateFormatter = new SimpleDateFormat("yyyyMMdd'T'HHmmss"); 4975f0c3a531938c0c1399efab94906aee74eff9108Bryan Mawhinney mDateFormatter.setTimeZone(TimeZone.getTimeZone("UTC")); 4985f0c3a531938c0c1399efab94906aee74eff9108Bryan Mawhinney } 4995f0c3a531938c0c1399efab94906aee74eff9108Bryan Mawhinney 50058ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen public FileEntry beginFile(String path, String mimeType, long lastModified, 501997354e4b4a9666cedd62282471e97822affced9Mike Lockwood long fileSize, boolean isDirectory, boolean noMedia) { 502076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood mMimeType = mimeType; 503076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood mFileType = 0; 504076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood mFileSize = fileSize; 50559c14048bfc0a210077192410afa28ed6f85daa0Erik Almqvist mIsDrm = false; 506bab75909fac9c65b71012f4c06302503c2f72be1Marco Nelissen mScanSuccess = true; 50720b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 508076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood if (!isDirectory) { 509ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood if (!noMedia && isNoMediaFile(path)) { 510ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood noMedia = true; 5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 512997354e4b4a9666cedd62282471e97822affced9Mike Lockwood mNoMedia = noMedia; 51320b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 514076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood // try mimeType first, if it is specified 515076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood if (mimeType != null) { 516076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood mFileType = MediaFile.getFileTypeForMimeType(mimeType); 517076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood } 5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 519076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood // if mimeType was not specified, compute file type based on file extension. 520076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood if (mFileType == 0) { 521076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood MediaFile.MediaFileType mediaFileType = MediaFile.getFileType(path); 522076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood if (mediaFileType != null) { 523076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood mFileType = mediaFileType.fileType; 524076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood if (mMimeType == null) { 525076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood mMimeType = mediaFileType.mimeType; 526076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood } 527858caeaaa1db4076565e6df06b2b2721ec453c4eMike Lockwood } 5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 52920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 530076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood if (isDrmEnabled() && MediaFile.isDrmFileType(mFileType)) { 531076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood mFileType = getFileTypeFromDrm(path); 532076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood } 5335d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang } 5345d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang 53558ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen FileEntry entry = makeEntryFor(path); 536a8a656b0c595fa876a387a91f8813f88a2d3abe7Marco Nelissen // add some slack to avoid a rounding error 537a8a656b0c595fa876a387a91f8813f88a2d3abe7Marco Nelissen long delta = (entry != null) ? (lastModified - entry.mLastModified) : 0; 538a8a656b0c595fa876a387a91f8813f88a2d3abe7Marco Nelissen boolean wasModified = delta > 1 || delta < -1; 539a8a656b0c595fa876a387a91f8813f88a2d3abe7Marco Nelissen if (entry == null || wasModified) { 540a8a656b0c595fa876a387a91f8813f88a2d3abe7Marco Nelissen if (wasModified) { 541a8a656b0c595fa876a387a91f8813f88a2d3abe7Marco Nelissen entry.mLastModified = lastModified; 542a8a656b0c595fa876a387a91f8813f88a2d3abe7Marco Nelissen } else { 54358ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen entry = new FileEntry(0, path, lastModified, 544a8a656b0c595fa876a387a91f8813f88a2d3abe7Marco Nelissen (isDirectory ? MtpConstants.FORMAT_ASSOCIATION : 0)); 545a8a656b0c595fa876a387a91f8813f88a2d3abe7Marco Nelissen } 5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project entry.mLastModifiedChanged = true; 5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 54820b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mProcessPlaylists && MediaFile.isPlayListFileType(mFileType)) { 5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPlayLists.add(entry); 5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // we don't process playlists in the main scan, so return null 5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 55420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // clear all the metadata 5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mArtist = null; 5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAlbumArtist = null; 5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAlbum = null; 5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mTitle = null; 5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mComposer = null; 5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mGenre = null; 5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mTrack = 0; 5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mYear = 0; 5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDuration = 0; 5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPath = path; 5665f0c3a531938c0c1399efab94906aee74eff9108Bryan Mawhinney mDate = 0; 5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLastModified = lastModified; 568c9706f0262a2f399f95e0d78ba2b7616e08d0069Sahil Sachdeva mWriter = null; 569f679ba7d944a403fbdc77926c44978ffd5161f2dMarco Nelissen mCompilation = 0; 570e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang mWidth = 0; 571e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang mHeight = 0; 57220b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return entry; 5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 57520b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 576bcbddd9342ee5ef48617ce7dcca6c505df3fcf08Marco Nelissen @Override 577997354e4b4a9666cedd62282471e97822affced9Mike Lockwood public void scanFile(String path, long lastModified, long fileSize, 578997354e4b4a9666cedd62282471e97822affced9Mike Lockwood boolean isDirectory, boolean noMedia) { 57900c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen // This is the callback funtion from native codes. 58000c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen // Log.v(TAG, "scanFile: "+path); 581997354e4b4a9666cedd62282471e97822affced9Mike Lockwood doScanFile(path, null, lastModified, fileSize, isDirectory, false, noMedia); 5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 584c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood public Uri doScanFile(String path, String mimeType, long lastModified, 585997354e4b4a9666cedd62282471e97822affced9Mike Lockwood long fileSize, boolean isDirectory, boolean scanAlways, boolean noMedia) { 5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Uri result = null; 5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// long t1 = System.currentTimeMillis(); 5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 58958ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen FileEntry entry = beginFile(path, mimeType, lastModified, 590997354e4b4a9666cedd62282471e97822affced9Mike Lockwood fileSize, isDirectory, noMedia); 59181e85bbf671f228600fba059e30cb22565bcfe9dMarco Nelissen 59268528911b9f74475ac79c369a6482f720259dbacMarco Nelissen if (entry == null) { 59368528911b9f74475ac79c369a6482f720259dbacMarco Nelissen return null; 59468528911b9f74475ac79c369a6482f720259dbacMarco Nelissen } 59568528911b9f74475ac79c369a6482f720259dbacMarco Nelissen 59681e85bbf671f228600fba059e30cb22565bcfe9dMarco Nelissen // if this file was just inserted via mtp, set the rowid to zero 59781e85bbf671f228600fba059e30cb22565bcfe9dMarco Nelissen // (even though it already exists in the database), to trigger 59881e85bbf671f228600fba059e30cb22565bcfe9dMarco Nelissen // the correct code path for updating its entry 59981e85bbf671f228600fba059e30cb22565bcfe9dMarco Nelissen if (mMtpObjectHandle != 0) { 60081e85bbf671f228600fba059e30cb22565bcfe9dMarco Nelissen entry.mRowId = 0; 60181e85bbf671f228600fba059e30cb22565bcfe9dMarco Nelissen } 60268528911b9f74475ac79c369a6482f720259dbacMarco Nelissen 60317d24400906235a172fc760e98656589692f798aJean-Michel Trivi if (entry.mPath != null) { 60417d24400906235a172fc760e98656589692f798aJean-Michel Trivi if (((!mDefaultNotificationSet && 60568528911b9f74475ac79c369a6482f720259dbacMarco Nelissen doesPathHaveFilename(entry.mPath, mDefaultNotificationFilename)) 60668528911b9f74475ac79c369a6482f720259dbacMarco Nelissen || (!mDefaultRingtoneSet && 60768528911b9f74475ac79c369a6482f720259dbacMarco Nelissen doesPathHaveFilename(entry.mPath, mDefaultRingtoneFilename)) 60868528911b9f74475ac79c369a6482f720259dbacMarco Nelissen || (!mDefaultAlarmSet && 60968528911b9f74475ac79c369a6482f720259dbacMarco Nelissen doesPathHaveFilename(entry.mPath, mDefaultAlarmAlertFilename)))) { 61017d24400906235a172fc760e98656589692f798aJean-Michel Trivi Log.w(TAG, "forcing rescan of " + entry.mPath + 61117d24400906235a172fc760e98656589692f798aJean-Michel Trivi "since ringtone setting didn't finish"); 61217d24400906235a172fc760e98656589692f798aJean-Michel Trivi scanAlways = true; 61317d24400906235a172fc760e98656589692f798aJean-Michel Trivi } else if (isSystemSoundWithMetadata(entry.mPath) 61417d24400906235a172fc760e98656589692f798aJean-Michel Trivi && !Build.FINGERPRINT.equals(sLastInternalScanFingerprint)) { 61517d24400906235a172fc760e98656589692f798aJean-Michel Trivi // file is located on the system partition where the date cannot be trusted: 61617d24400906235a172fc760e98656589692f798aJean-Michel Trivi // rescan if the build fingerprint has changed since the last scan. 61717d24400906235a172fc760e98656589692f798aJean-Michel Trivi Log.i(TAG, "forcing rescan of " + entry.mPath 61817d24400906235a172fc760e98656589692f798aJean-Michel Trivi + " since build fingerprint changed"); 61917d24400906235a172fc760e98656589692f798aJean-Michel Trivi scanAlways = true; 62017d24400906235a172fc760e98656589692f798aJean-Michel Trivi } 62168528911b9f74475ac79c369a6482f720259dbacMarco Nelissen } 62268528911b9f74475ac79c369a6482f720259dbacMarco Nelissen 6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // rescan for metadata if file was modified since last scan 6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (entry != null && (entry.mLastModifiedChanged || scanAlways)) { 625997354e4b4a9666cedd62282471e97822affced9Mike Lockwood if (noMedia) { 626997354e4b4a9666cedd62282471e97822affced9Mike Lockwood result = endFile(entry, false, false, false, false, false); 627997354e4b4a9666cedd62282471e97822affced9Mike Lockwood } else { 628c861411d4bae0912054ff54c3efee90ae2db6db9Marco Nelissen boolean isaudio = MediaFile.isAudioFileType(mFileType); 629c861411d4bae0912054ff54c3efee90ae2db6db9Marco Nelissen boolean isvideo = MediaFile.isVideoFileType(mFileType); 630c861411d4bae0912054ff54c3efee90ae2db6db9Marco Nelissen boolean isimage = MediaFile.isImageFileType(mFileType); 631c861411d4bae0912054ff54c3efee90ae2db6db9Marco Nelissen 632c861411d4bae0912054ff54c3efee90ae2db6db9Marco Nelissen if (isaudio || isvideo || isimage) { 6334887789e44cdb16b042a35e8ec03983213e88ac6Jeff Sharkey path = Environment.maybeTranslateEmulatedPathToInternal(new File(path)) 6344887789e44cdb16b042a35e8ec03983213e88ac6Jeff Sharkey .getAbsolutePath(); 635c861411d4bae0912054ff54c3efee90ae2db6db9Marco Nelissen } 636c861411d4bae0912054ff54c3efee90ae2db6db9Marco Nelissen 637997354e4b4a9666cedd62282471e97822affced9Mike Lockwood // we only extract metadata for audio and video files 638c861411d4bae0912054ff54c3efee90ae2db6db9Marco Nelissen if (isaudio || isvideo) { 639bab75909fac9c65b71012f4c06302503c2f72be1Marco Nelissen mScanSuccess = processFile(path, mimeType, this); 640997354e4b4a9666cedd62282471e97822affced9Mike Lockwood } 64120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 642c861411d4bae0912054ff54c3efee90ae2db6db9Marco Nelissen if (isimage) { 643bab75909fac9c65b71012f4c06302503c2f72be1Marco Nelissen mScanSuccess = processImageFile(path); 644e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang } 645e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang 646bab75909fac9c65b71012f4c06302503c2f72be1Marco Nelissen String lowpath = path.toLowerCase(Locale.ROOT); 647bab75909fac9c65b71012f4c06302503c2f72be1Marco Nelissen boolean ringtones = mScanSuccess && (lowpath.indexOf(RINGTONES_DIR) > 0); 648bab75909fac9c65b71012f4c06302503c2f72be1Marco Nelissen boolean notifications = mScanSuccess && 649bab75909fac9c65b71012f4c06302503c2f72be1Marco Nelissen (lowpath.indexOf(NOTIFICATIONS_DIR) > 0); 650bab75909fac9c65b71012f4c06302503c2f72be1Marco Nelissen boolean alarms = mScanSuccess && (lowpath.indexOf(ALARMS_DIR) > 0); 651bab75909fac9c65b71012f4c06302503c2f72be1Marco Nelissen boolean podcasts = mScanSuccess && (lowpath.indexOf(PODCAST_DIR) > 0); 652bab75909fac9c65b71012f4c06302503c2f72be1Marco Nelissen boolean music = mScanSuccess && ((lowpath.indexOf(MUSIC_DIR) > 0) || 653bab75909fac9c65b71012f4c06302503c2f72be1Marco Nelissen (!ringtones && !notifications && !alarms && !podcasts)); 654bab75909fac9c65b71012f4c06302503c2f72be1Marco Nelissen 655997354e4b4a9666cedd62282471e97822affced9Mike Lockwood result = endFile(entry, ringtones, notifications, alarms, music, podcasts); 656997354e4b4a9666cedd62282471e97822affced9Mike Lockwood } 6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (RemoteException e) { 6599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "RemoteException in MediaScanner.scanFile()", e); 6609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// long t2 = System.currentTimeMillis(); 6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// Log.v(TAG, "scanFile: " + path + " took " + (t2-t1)); 6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return result; 6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6665f0c3a531938c0c1399efab94906aee74eff9108Bryan Mawhinney private long parseDate(String date) { 6675f0c3a531938c0c1399efab94906aee74eff9108Bryan Mawhinney try { 6685f0c3a531938c0c1399efab94906aee74eff9108Bryan Mawhinney return mDateFormatter.parse(date).getTime(); 6695f0c3a531938c0c1399efab94906aee74eff9108Bryan Mawhinney } catch (ParseException e) { 6705f0c3a531938c0c1399efab94906aee74eff9108Bryan Mawhinney return 0; 6715f0c3a531938c0c1399efab94906aee74eff9108Bryan Mawhinney } 6725f0c3a531938c0c1399efab94906aee74eff9108Bryan Mawhinney } 6735f0c3a531938c0c1399efab94906aee74eff9108Bryan Mawhinney 6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int parseSubstring(String s, int start, int defaultValue) { 6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int length = s.length(); 6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (start == length) return defaultValue; 6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char ch = s.charAt(start++); 6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // return defaultValue if we have no integer at all 6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (ch < '0' || ch > '9') return defaultValue; 68120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 6829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int result = ch - '0'; 6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (start < length) { 6849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ch = s.charAt(start++); 6859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (ch < '0' || ch > '9') return result; 6869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project result = result * 10 + (ch - '0'); 6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 68820b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return result; 69020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync } 69120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 6929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void handleStringTag(String name, String value) { 6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (name.equalsIgnoreCase("title") || name.startsWith("title;")) { 69473bb511adee5444ecd041146fbbd3677fb635949Marco Nelissen // Don't trim() here, to preserve the special \001 character 69573bb511adee5444ecd041146fbbd3677fb635949Marco Nelissen // used to force sorting. The media provider will trim() before 69673bb511adee5444ecd041146fbbd3677fb635949Marco Nelissen // inserting the title in to the database. 69773bb511adee5444ecd041146fbbd3677fb635949Marco Nelissen mTitle = value; 6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (name.equalsIgnoreCase("artist") || name.startsWith("artist;")) { 6999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mArtist = value.trim(); 700ed8188711a794867b47d21bbed3e26827f6c27e3Neel Parekh } else if (name.equalsIgnoreCase("albumartist") || name.startsWith("albumartist;") 701ed8188711a794867b47d21bbed3e26827f6c27e3Neel Parekh || name.equalsIgnoreCase("band") || name.startsWith("band;")) { 7029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAlbumArtist = value.trim(); 7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (name.equalsIgnoreCase("album") || name.startsWith("album;")) { 7049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAlbum = value.trim(); 7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (name.equalsIgnoreCase("composer") || name.startsWith("composer;")) { 7069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mComposer = value.trim(); 70743b076bb75e86fbb34cbe36aa0298c7a647121ffMike Lockwood } else if (mProcessGenres && 70843b076bb75e86fbb34cbe36aa0298c7a647121ffMike Lockwood (name.equalsIgnoreCase("genre") || name.startsWith("genre;"))) { 709cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen mGenre = getGenreName(value); 7109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (name.equalsIgnoreCase("year") || name.startsWith("year;")) { 7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mYear = parseSubstring(value, 0, 0); 7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (name.equalsIgnoreCase("tracknumber") || name.startsWith("tracknumber;")) { 7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // track number might be of the form "2/12" 7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // we just read the number before the slash 7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int num = parseSubstring(value, 0, 0); 71620b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync mTrack = (mTrack / 1000) * 1000 + num; 7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (name.equalsIgnoreCase("discnumber") || 7189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project name.equals("set") || name.startsWith("set;")) { 7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // set number might be of the form "1/3" 7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // we just read the number before the slash 7219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int num = parseSubstring(value, 0, 0); 7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mTrack = (num * 1000) + (mTrack % 1000); 7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (name.equalsIgnoreCase("duration")) { 7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDuration = parseSubstring(value, 0, 0); 725c9706f0262a2f399f95e0d78ba2b7616e08d0069Sahil Sachdeva } else if (name.equalsIgnoreCase("writer") || name.startsWith("writer;")) { 726c9706f0262a2f399f95e0d78ba2b7616e08d0069Sahil Sachdeva mWriter = value.trim(); 727f679ba7d944a403fbdc77926c44978ffd5161f2dMarco Nelissen } else if (name.equalsIgnoreCase("compilation")) { 728f679ba7d944a403fbdc77926c44978ffd5161f2dMarco Nelissen mCompilation = parseSubstring(value, 0, 0); 72982428a862f325238cfb5646bbd65de3f1a11e7ccGloria Wang } else if (name.equalsIgnoreCase("isdrm")) { 73082428a862f325238cfb5646bbd65de3f1a11e7ccGloria Wang mIsDrm = (parseSubstring(value, 0, 0) == 1); 7315f0c3a531938c0c1399efab94906aee74eff9108Bryan Mawhinney } else if (name.equalsIgnoreCase("date")) { 7325f0c3a531938c0c1399efab94906aee74eff9108Bryan Mawhinney mDate = parseDate(value); 733e313f721ad97ad44666dd066a891acb4ddfa8ab3Marco Nelissen } else if (name.equalsIgnoreCase("width")) { 734e313f721ad97ad44666dd066a891acb4ddfa8ab3Marco Nelissen mWidth = parseSubstring(value, 0, 0); 735e313f721ad97ad44666dd066a891acb4ddfa8ab3Marco Nelissen } else if (name.equalsIgnoreCase("height")) { 736e313f721ad97ad44666dd066a891acb4ddfa8ab3Marco Nelissen mHeight = parseSubstring(value, 0, 0); 737ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen } else { 738ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen //Log.v(TAG, "unknown tag: " + name + " (" + mProcessGenres + ")"); 7399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 74120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 742ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen private boolean convertGenreCode(String input, String expected) { 743ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen String output = getGenreName(input); 744ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen if (output.equals(expected)) { 745ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen return true; 746ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen } else { 747ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen Log.d(TAG, "'" + input + "' -> '" + output + "', expected '" + expected + "'"); 748ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen return false; 749ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen } 750ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen } 751ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen private void testGenreNameConverter() { 752ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen convertGenreCode("2", "Country"); 753ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen convertGenreCode("(2)", "Country"); 754ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen convertGenreCode("(2", "(2"); 755ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen convertGenreCode("2 Foo", "Country"); 756ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen convertGenreCode("(2) Foo", "Country"); 757ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen convertGenreCode("(2 Foo", "(2 Foo"); 758ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen convertGenreCode("2Foo", "2Foo"); 759ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen convertGenreCode("(2)Foo", "Country"); 760ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen convertGenreCode("200 Foo", "Foo"); 761ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen convertGenreCode("(200) Foo", "Foo"); 762ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen convertGenreCode("200Foo", "200Foo"); 763ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen convertGenreCode("(200)Foo", "Foo"); 764ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen convertGenreCode("200)Foo", "200)Foo"); 765ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen convertGenreCode("200) Foo", "200) Foo"); 766ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen } 767ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen 768cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen public String getGenreName(String genreTagValue) { 769cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen 770cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen if (genreTagValue == null) { 771cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen return null; 772cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen } 773cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen final int length = genreTagValue.length(); 774cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen 775ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen if (length > 0) { 776ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen boolean parenthesized = false; 777cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen StringBuffer number = new StringBuffer(); 778ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen int i = 0; 779ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen for (; i < length; ++i) { 780cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen char c = genreTagValue.charAt(i); 781ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen if (i == 0 && c == '(') { 782ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen parenthesized = true; 783ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen } else if (Character.isDigit(c)) { 784cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen number.append(c); 785cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen } else { 786cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen break; 787cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen } 788cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen } 789ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen char charAfterNumber = i < length ? genreTagValue.charAt(i) : ' '; 790ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen if ((parenthesized && charAfterNumber == ')') 791ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen || !parenthesized && Character.isWhitespace(charAfterNumber)) { 792cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen try { 793cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen short genreIndex = Short.parseShort(number.toString()); 794cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen if (genreIndex >= 0) { 795c3ea477e2111f199d10341b121791cb2ec91eca3Johan Redestig if (genreIndex < ID3_GENRES.length && ID3_GENRES[genreIndex] != null) { 796cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen return ID3_GENRES[genreIndex]; 797cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen } else if (genreIndex == 0xFF) { 798cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen return null; 799cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen } else if (genreIndex < 0xFF && (i + 1) < length) { 800cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen // genre is valid but unknown, 801cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen // if there is a string after the value we take it 802ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen if (parenthesized && charAfterNumber == ')') { 803ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen i++; 804ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen } 805ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen String ret = genreTagValue.substring(i).trim(); 806ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen if (ret.length() != 0) { 807ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen return ret; 808ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen } 809cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen } else { 810cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen // else return the number, without parentheses 811cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen return number.toString(); 812cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen } 813cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen } 814cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen } catch (NumberFormatException e) { 815cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen } 816cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen } 817cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen } 818cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen 819cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen return genreTagValue; 820cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen } 821cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen 822bab75909fac9c65b71012f4c06302503c2f72be1Marco Nelissen private boolean processImageFile(String path) { 823e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang try { 824e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang mBitmapOptions.outWidth = 0; 825e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang mBitmapOptions.outHeight = 0; 826e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang BitmapFactory.decodeFile(path, mBitmapOptions); 827e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang mWidth = mBitmapOptions.outWidth; 828e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang mHeight = mBitmapOptions.outHeight; 829bab75909fac9c65b71012f4c06302503c2f72be1Marco Nelissen return mWidth > 0 && mHeight > 0; 830e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang } catch (Throwable th) { 831e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang // ignore; 832e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang } 833bab75909fac9c65b71012f4c06302503c2f72be1Marco Nelissen return false; 834e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang } 835e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang 8369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setMimeType(String mimeType) { 8371851db6804cbdf8d2c8ede0725e73be6fda0f3c0Marco Nelissen if ("audio/mp4".equals(mMimeType) && 8381851db6804cbdf8d2c8ede0725e73be6fda0f3c0Marco Nelissen mimeType.startsWith("video")) { 8391851db6804cbdf8d2c8ede0725e73be6fda0f3c0Marco Nelissen // for feature parity with Donut, we force m4a files to keep the 8401851db6804cbdf8d2c8ede0725e73be6fda0f3c0Marco Nelissen // audio/mp4 mimetype, even if they are really "enhanced podcasts" 8411851db6804cbdf8d2c8ede0725e73be6fda0f3c0Marco Nelissen // with a video track 8421851db6804cbdf8d2c8ede0725e73be6fda0f3c0Marco Nelissen return; 8431851db6804cbdf8d2c8ede0725e73be6fda0f3c0Marco Nelissen } 8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMimeType = mimeType; 8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mFileType = MediaFile.getFileTypeForMimeType(mimeType); 8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 84720b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 8489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 8499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Formats the data into a values array suitable for use with the Media 8509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Content Provider. 85120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync * 8529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return a map of values 8539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private ContentValues toValues() { 8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ContentValues map = new ContentValues(); 8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project map.put(MediaStore.MediaColumns.DATA, mPath); 8589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project map.put(MediaStore.MediaColumns.TITLE, mTitle); 8599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project map.put(MediaStore.MediaColumns.DATE_MODIFIED, mLastModified); 8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project map.put(MediaStore.MediaColumns.SIZE, mFileSize); 8619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project map.put(MediaStore.MediaColumns.MIME_TYPE, mMimeType); 86282428a862f325238cfb5646bbd65de3f1a11e7ccGloria Wang map.put(MediaStore.MediaColumns.IS_DRM, mIsDrm); 86320b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 864e313f721ad97ad44666dd066a891acb4ddfa8ab3Marco Nelissen String resolution = null; 865e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang if (mWidth > 0 && mHeight > 0) { 866e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang map.put(MediaStore.MediaColumns.WIDTH, mWidth); 867e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang map.put(MediaStore.MediaColumns.HEIGHT, mHeight); 868e313f721ad97ad44666dd066a891acb4ddfa8ab3Marco Nelissen resolution = mWidth + "x" + mHeight; 869e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang } 870e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang 871e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood if (!mNoMedia) { 872997354e4b4a9666cedd62282471e97822affced9Mike Lockwood if (MediaFile.isVideoFileType(mFileType)) { 873997354e4b4a9666cedd62282471e97822affced9Mike Lockwood map.put(Video.Media.ARTIST, (mArtist != null && mArtist.length() > 0 874997354e4b4a9666cedd62282471e97822affced9Mike Lockwood ? mArtist : MediaStore.UNKNOWN_STRING)); 875997354e4b4a9666cedd62282471e97822affced9Mike Lockwood map.put(Video.Media.ALBUM, (mAlbum != null && mAlbum.length() > 0 876997354e4b4a9666cedd62282471e97822affced9Mike Lockwood ? mAlbum : MediaStore.UNKNOWN_STRING)); 877997354e4b4a9666cedd62282471e97822affced9Mike Lockwood map.put(Video.Media.DURATION, mDuration); 878e313f721ad97ad44666dd066a891acb4ddfa8ab3Marco Nelissen if (resolution != null) { 879e313f721ad97ad44666dd066a891acb4ddfa8ab3Marco Nelissen map.put(Video.Media.RESOLUTION, resolution); 880e313f721ad97ad44666dd066a891acb4ddfa8ab3Marco Nelissen } 8815f0c3a531938c0c1399efab94906aee74eff9108Bryan Mawhinney if (mDate > 0) { 8825f0c3a531938c0c1399efab94906aee74eff9108Bryan Mawhinney map.put(Video.Media.DATE_TAKEN, mDate); 8835f0c3a531938c0c1399efab94906aee74eff9108Bryan Mawhinney } 884997354e4b4a9666cedd62282471e97822affced9Mike Lockwood } else if (MediaFile.isImageFileType(mFileType)) { 885997354e4b4a9666cedd62282471e97822affced9Mike Lockwood // FIXME - add DESCRIPTION 886bab75909fac9c65b71012f4c06302503c2f72be1Marco Nelissen } else if (mScanSuccess && MediaFile.isAudioFileType(mFileType)) { 887997354e4b4a9666cedd62282471e97822affced9Mike Lockwood map.put(Audio.Media.ARTIST, (mArtist != null && mArtist.length() > 0) ? 888997354e4b4a9666cedd62282471e97822affced9Mike Lockwood mArtist : MediaStore.UNKNOWN_STRING); 889997354e4b4a9666cedd62282471e97822affced9Mike Lockwood map.put(Audio.Media.ALBUM_ARTIST, (mAlbumArtist != null && 890997354e4b4a9666cedd62282471e97822affced9Mike Lockwood mAlbumArtist.length() > 0) ? mAlbumArtist : null); 891997354e4b4a9666cedd62282471e97822affced9Mike Lockwood map.put(Audio.Media.ALBUM, (mAlbum != null && mAlbum.length() > 0) ? 892997354e4b4a9666cedd62282471e97822affced9Mike Lockwood mAlbum : MediaStore.UNKNOWN_STRING); 893997354e4b4a9666cedd62282471e97822affced9Mike Lockwood map.put(Audio.Media.COMPOSER, mComposer); 894e5d0495d5206167c597efcd81436a0f881f069f9Mike Lockwood map.put(Audio.Media.GENRE, mGenre); 895997354e4b4a9666cedd62282471e97822affced9Mike Lockwood if (mYear != 0) { 896997354e4b4a9666cedd62282471e97822affced9Mike Lockwood map.put(Audio.Media.YEAR, mYear); 897997354e4b4a9666cedd62282471e97822affced9Mike Lockwood } 898997354e4b4a9666cedd62282471e97822affced9Mike Lockwood map.put(Audio.Media.TRACK, mTrack); 899997354e4b4a9666cedd62282471e97822affced9Mike Lockwood map.put(Audio.Media.DURATION, mDuration); 900997354e4b4a9666cedd62282471e97822affced9Mike Lockwood map.put(Audio.Media.COMPILATION, mCompilation); 9019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 902bab75909fac9c65b71012f4c06302503c2f72be1Marco Nelissen if (!mScanSuccess) { 903bab75909fac9c65b71012f4c06302503c2f72be1Marco Nelissen // force mediaprovider to not determine the media type from the mime type 904bab75909fac9c65b71012f4c06302503c2f72be1Marco Nelissen map.put(Files.FileColumns.MEDIA_TYPE, 0); 905bab75909fac9c65b71012f4c06302503c2f72be1Marco Nelissen } 9069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return map; 9089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 90920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 91058ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen private Uri endFile(FileEntry entry, boolean ringtones, boolean notifications, 91120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync boolean alarms, boolean music, boolean podcasts) 9129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throws RemoteException { 9139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // update database 91420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 915997354e4b4a9666cedd62282471e97822affced9Mike Lockwood // use album artist if artist is missing 9169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mArtist == null || mArtist.length() == 0) { 9179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mArtist = mAlbumArtist; 9189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ContentValues values = toValues(); 9219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String title = values.getAsString(MediaStore.MediaColumns.TITLE); 922bdc0e82f9c075edb67da4a2583e557824c280415Mike Lockwood if (title == null || TextUtils.isEmpty(title.trim())) { 923c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood title = MediaFile.getFileTitle(values.getAsString(MediaStore.MediaColumns.DATA)); 9249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project values.put(MediaStore.MediaColumns.TITLE, title); 9259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 926c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen String album = values.getAsString(Audio.Media.ALBUM); 9279a488b44cb479bc42375d2cfcdd4aa6161dc17cfMarco Nelissen if (MediaStore.UNKNOWN_STRING.equals(album)) { 928c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen album = values.getAsString(MediaStore.MediaColumns.DATA); 929c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen // extract last path segment before file name 930c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen int lastSlash = album.lastIndexOf('/'); 931c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen if (lastSlash >= 0) { 932c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen int previousSlash = 0; 933c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen while (true) { 934c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen int idx = album.indexOf('/', previousSlash + 1); 935c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen if (idx < 0 || idx >= lastSlash) { 936c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen break; 937c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen } 938c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen previousSlash = idx; 939c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen } 940c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen if (previousSlash != 0) { 941c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen album = album.substring(previousSlash + 1, lastSlash); 942c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen values.put(Audio.Media.ALBUM, album); 943c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen } 944c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen } 945c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen } 946c066557378c2305625a7bad3d25f084ad647ef27Marco Nelissen long rowId = entry.mRowId; 947c2206a0710a3ca2c29854c1a0638c5ba55629ba2Mike Lockwood if (MediaFile.isAudioFileType(mFileType) && (rowId == 0 || mMtpObjectHandle != 0)) { 948c066557378c2305625a7bad3d25f084ad647ef27Marco Nelissen // Only set these for new entries. For existing entries, they 949c066557378c2305625a7bad3d25f084ad647ef27Marco Nelissen // may have been modified later, and we want to keep the current 950c066557378c2305625a7bad3d25f084ad647ef27Marco Nelissen // values so that custom ringtones still show up in the ringtone 951c066557378c2305625a7bad3d25f084ad647ef27Marco Nelissen // picker. 9529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project values.put(Audio.Media.IS_RINGTONE, ringtones); 9539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project values.put(Audio.Media.IS_NOTIFICATION, notifications); 9549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project values.put(Audio.Media.IS_ALARM, alarms); 9559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project values.put(Audio.Media.IS_MUSIC, music); 9569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project values.put(Audio.Media.IS_PODCAST, podcasts); 9575a8b9627c7fdacc94791fb3024386739f8cf9a56Jaesung Chung } else if ((mFileType == MediaFile.FILE_TYPE_JPEG 9583edfdab205ea061493d25284cd720665c285759bChong Zhang || mFileType == MediaFile.FILE_TYPE_HEIF 9595a8b9627c7fdacc94791fb3024386739f8cf9a56Jaesung Chung || MediaFile.isRawImageFileType(mFileType)) && !mNoMedia) { 960700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang ExifInterface exif = null; 961700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang try { 962700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang exif = new ExifInterface(entry.mPath); 963700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang } catch (IOException ex) { 964700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang // exif is null 965700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang } 966700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang if (exif != null) { 967872a30ec723ebdd97de764406544516545d7c9d4Chih-Chung Chang float[] latlng = new float[2]; 968872a30ec723ebdd97de764406544516545d7c9d4Chih-Chung Chang if (exif.getLatLong(latlng)) { 96920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync values.put(Images.Media.LATITUDE, latlng[0]); 97020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync values.put(Images.Media.LONGITUDE, latlng[1]); 97120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync } 972099397cbd07c8c991f3126d0d0ac64bb6b3c0b47Chih-Chung Chang 9733a8cab88e7747dc280ce85895af014f98e80a6ccRay Chen long time = exif.getGpsDateTime(); 974099397cbd07c8c991f3126d0d0ac64bb6b3c0b47Chih-Chung Chang if (time != -1) { 975052d9c8b414dc9eb1c70d849660592d9bc3b2644Ray Chen values.put(Images.Media.DATE_TAKEN, time); 976a2c322f599b5a44ca153922b994a05a4311331cbRay Chen } else { 977a2c322f599b5a44ca153922b994a05a4311331cbRay Chen // If no time zone information is available, we should consider using 978a2c322f599b5a44ca153922b994a05a4311331cbRay Chen // EXIF local time as taken time if the difference between file time 979a2c322f599b5a44ca153922b994a05a4311331cbRay Chen // and EXIF local time is not less than 1 Day, otherwise MediaProvider 980a2c322f599b5a44ca153922b994a05a4311331cbRay Chen // will use file time as taken time. 981a2c322f599b5a44ca153922b994a05a4311331cbRay Chen time = exif.getDateTime(); 982872e7b7073fad8295e6314c73b87d7cb3f85d39cRay Chen if (time != -1 && Math.abs(mLastModified * 1000 - time) >= 86400000) { 983a2c322f599b5a44ca153922b994a05a4311331cbRay Chen values.put(Images.Media.DATE_TAKEN, time); 984a2c322f599b5a44ca153922b994a05a4311331cbRay Chen } 985099397cbd07c8c991f3126d0d0ac64bb6b3c0b47Chih-Chung Chang } 986b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang 987b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang int orientation = exif.getAttributeInt( 988b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang ExifInterface.TAG_ORIENTATION, -1); 989b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang if (orientation != -1) { 990b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang // We only recognize a subset of orientation tag values. 991b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang int degree; 992b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang switch(orientation) { 993b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang case ExifInterface.ORIENTATION_ROTATE_90: 994b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang degree = 90; 995b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang break; 996b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang case ExifInterface.ORIENTATION_ROTATE_180: 997b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang degree = 180; 998b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang break; 999b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang case ExifInterface.ORIENTATION_ROTATE_270: 1000b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang degree = 270; 1001b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang break; 1002b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang default: 1003b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang degree = 0; 1004b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang break; 1005b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang } 1006b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang values.put(Images.Media.ORIENTATION, degree); 1007b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang } 100820b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync } 10099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 101020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 101145aaa2a345292bb6d600822db602f25e261c0e50Mike Lockwood Uri tableUri = mFilesUri; 10128e2ed8d512ade2ea481b3a292556782b17a74674Dongwon Kang MediaInserter inserter = mMediaInserter; 1013bab75909fac9c65b71012f4c06302503c2f72be1Marco Nelissen if (mScanSuccess && !mNoMedia) { 1014e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood if (MediaFile.isVideoFileType(mFileType)) { 1015e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood tableUri = mVideoUri; 1016e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood } else if (MediaFile.isImageFileType(mFileType)) { 1017e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood tableUri = mImagesUri; 1018e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood } else if (MediaFile.isAudioFileType(mFileType)) { 1019e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood tableUri = mAudioUri; 1020e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood } 1021e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood } 10229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Uri result = null; 10236c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim boolean needToSetSettings = false; 102468528911b9f74475ac79c369a6482f720259dbacMarco Nelissen // Setting a flag in order not to use bulk insert for the file related with 102568528911b9f74475ac79c369a6482f720259dbacMarco Nelissen // notifications, ringtones, and alarms, because the rowId of the inserted file is 102668528911b9f74475ac79c369a6482f720259dbacMarco Nelissen // needed. 102768528911b9f74475ac79c369a6482f720259dbacMarco Nelissen if (notifications && !mDefaultNotificationSet) { 102868528911b9f74475ac79c369a6482f720259dbacMarco Nelissen if (TextUtils.isEmpty(mDefaultNotificationFilename) || 102968528911b9f74475ac79c369a6482f720259dbacMarco Nelissen doesPathHaveFilename(entry.mPath, mDefaultNotificationFilename)) { 103068528911b9f74475ac79c369a6482f720259dbacMarco Nelissen needToSetSettings = true; 103168528911b9f74475ac79c369a6482f720259dbacMarco Nelissen } 103268528911b9f74475ac79c369a6482f720259dbacMarco Nelissen } else if (ringtones && !mDefaultRingtoneSet) { 103368528911b9f74475ac79c369a6482f720259dbacMarco Nelissen if (TextUtils.isEmpty(mDefaultRingtoneFilename) || 103468528911b9f74475ac79c369a6482f720259dbacMarco Nelissen doesPathHaveFilename(entry.mPath, mDefaultRingtoneFilename)) { 103568528911b9f74475ac79c369a6482f720259dbacMarco Nelissen needToSetSettings = true; 103668528911b9f74475ac79c369a6482f720259dbacMarco Nelissen } 103768528911b9f74475ac79c369a6482f720259dbacMarco Nelissen } else if (alarms && !mDefaultAlarmSet) { 103868528911b9f74475ac79c369a6482f720259dbacMarco Nelissen if (TextUtils.isEmpty(mDefaultAlarmAlertFilename) || 103968528911b9f74475ac79c369a6482f720259dbacMarco Nelissen doesPathHaveFilename(entry.mPath, mDefaultAlarmAlertFilename)) { 104068528911b9f74475ac79c369a6482f720259dbacMarco Nelissen needToSetSettings = true; 104168528911b9f74475ac79c369a6482f720259dbacMarco Nelissen } 104268528911b9f74475ac79c369a6482f720259dbacMarco Nelissen } 104368528911b9f74475ac79c369a6482f720259dbacMarco Nelissen 10449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (rowId == 0) { 1045c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood if (mMtpObjectHandle != 0) { 1046c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood values.put(MediaStore.MediaColumns.MEDIA_SCANNER_NEW_OBJECT_ID, mMtpObjectHandle); 1047c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood } 1048e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood if (tableUri == mFilesUri) { 1049e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood int format = entry.mFormat; 1050e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood if (format == 0) { 1051e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood format = MediaFile.getFormatCode(entry.mPath, mMimeType); 1052e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood } 1053e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood values.put(Files.FileColumns.FORMAT, format); 1054c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood } 1055d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen // New file, insert it. 1056d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen // Directories need to be inserted before the files they contain, so they 1057d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen // get priority when bulk inserting. 1058d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen // If the rowId of the inserted file is needed, it gets inserted immediately, 1059d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen // bypassing the bulk inserter. 1060d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen if (inserter == null || needToSetSettings) { 1061299942002b17f792e6e4f6b3f6972f62b8b136aeMarco Nelissen if (inserter != null) { 1062299942002b17f792e6e4f6b3f6972f62b8b136aeMarco Nelissen inserter.flushAll(); 1063299942002b17f792e6e4f6b3f6972f62b8b136aeMarco Nelissen } 106460cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey result = mMediaProvider.insert(tableUri, values); 1065d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen } else if (entry.mFormat == MtpConstants.FORMAT_ASSOCIATION) { 1066d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen inserter.insertwithPriority(tableUri, values); 1067c6eaa713a3f5b9337eca60ba2ab570cf6e80c357Mike Lockwood } else { 10688e2ed8d512ade2ea481b3a292556782b17a74674Dongwon Kang inserter.insert(tableUri, values); 1069bd682b040833fce9e212c00c395b32bec7050f87Mike Lockwood } 1070bd682b040833fce9e212c00c395b32bec7050f87Mike Lockwood 10719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (result != null) { 10729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project rowId = ContentUris.parseId(result); 10739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project entry.mRowId = rowId; 10749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 10769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // updated file 107745aaa2a345292bb6d600822db602f25e261c0e50Mike Lockwood result = ContentUris.withAppendedId(tableUri, rowId); 10780dd9f4de3ed681e83bd79ddcd4fd463093d11ed3Mike Lockwood // path should never change, and we want to avoid replacing mixed cased paths 10790dd9f4de3ed681e83bd79ddcd4fd463093d11ed3Mike Lockwood // with squashed lower case paths 10800dd9f4de3ed681e83bd79ddcd4fd463093d11ed3Mike Lockwood values.remove(MediaStore.MediaColumns.DATA); 1081ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen 1082ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen int mediaType = 0; 1083bab75909fac9c65b71012f4c06302503c2f72be1Marco Nelissen if (mScanSuccess && !MediaScanner.isNoMediaPath(entry.mPath)) { 1084ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen int fileType = MediaFile.getFileTypeForMimeType(mMimeType); 1085ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen if (MediaFile.isAudioFileType(fileType)) { 1086ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen mediaType = FileColumns.MEDIA_TYPE_AUDIO; 1087ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen } else if (MediaFile.isVideoFileType(fileType)) { 1088ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen mediaType = FileColumns.MEDIA_TYPE_VIDEO; 1089ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen } else if (MediaFile.isImageFileType(fileType)) { 1090ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen mediaType = FileColumns.MEDIA_TYPE_IMAGE; 1091ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen } else if (MediaFile.isPlayListFileType(fileType)) { 1092ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen mediaType = FileColumns.MEDIA_TYPE_PLAYLIST; 1093ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen } 1094ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen values.put(FileColumns.MEDIA_TYPE, mediaType); 1095ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen } 109660cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey mMediaProvider.update(result, values, null, null); 10979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 109820b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 10996c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim if(needToSetSettings) { 11006c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim if (notifications) { 11019dd3b2162dd308762a023ad07a39c2379bcbf931Jeff Sharkey setRingtoneIfNotSet(Settings.System.NOTIFICATION_SOUND, tableUri, rowId); 11029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDefaultNotificationSet = true; 11036c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim } else if (ringtones) { 11049dd3b2162dd308762a023ad07a39c2379bcbf931Jeff Sharkey setRingtoneIfNotSet(Settings.System.RINGTONE, tableUri, rowId); 11059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDefaultRingtoneSet = true; 11066c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim } else if (alarms) { 11079dd3b2162dd308762a023ad07a39c2379bcbf931Jeff Sharkey setRingtoneIfNotSet(Settings.System.ALARM_ALERT, tableUri, rowId); 11083156bb00dd3ab3d6ec732bb6a64a2e84d08c34f0Patrick Scott mDefaultAlarmSet = true; 11093156bb00dd3ab3d6ec732bb6a64a2e84d08c34f0Patrick Scott } 11109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 111120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 11129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return result; 11139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 111420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 11159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean doesPathHaveFilename(String path, String filename) { 11169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int pathFilenameStart = path.lastIndexOf(File.separatorChar) + 1; 11179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int filenameLength = filename.length(); 11189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return path.regionMatches(pathFilenameStart, filename, 0, filenameLength) && 11199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project pathFilenameStart + filenameLength == path.length(); 11209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 112120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 11229dd3b2162dd308762a023ad07a39c2379bcbf931Jeff Sharkey private void setRingtoneIfNotSet(String settingName, Uri uri, long rowId) { 11239dd3b2162dd308762a023ad07a39c2379bcbf931Jeff Sharkey if (wasRingtoneAlreadySet(settingName)) { 112468528911b9f74475ac79c369a6482f720259dbacMarco Nelissen return; 112568528911b9f74475ac79c369a6482f720259dbacMarco Nelissen } 112620b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 112768528911b9f74475ac79c369a6482f720259dbacMarco Nelissen ContentResolver cr = mContext.getContentResolver(); 112868528911b9f74475ac79c369a6482f720259dbacMarco Nelissen String existingSettingValue = Settings.System.getString(cr, settingName); 11299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (TextUtils.isEmpty(existingSettingValue)) { 11309dd3b2162dd308762a023ad07a39c2379bcbf931Jeff Sharkey final Uri settingUri = Settings.System.getUriFor(settingName); 11319dd3b2162dd308762a023ad07a39c2379bcbf931Jeff Sharkey final Uri ringtoneUri = ContentUris.withAppendedId(uri, rowId); 11329dd3b2162dd308762a023ad07a39c2379bcbf931Jeff Sharkey RingtoneManager.setActualDefaultRingtoneUri(mContext, 11339dd3b2162dd308762a023ad07a39c2379bcbf931Jeff Sharkey RingtoneManager.getDefaultType(settingUri), ringtoneUri); 11349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 113568528911b9f74475ac79c369a6482f720259dbacMarco Nelissen Settings.System.putInt(cr, settingSetIndicatorName(settingName), 1); 11369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 113720b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 11385d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang private int getFileTypeFromDrm(String path) { 1139e4eb4d9de37a8e9ed6f43a5f7deccf88f28bfc8bMarco Nelissen if (!isDrmEnabled()) { 11405d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang return 0; 11415d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang } 11425d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang 11435d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang int resultFileType = 0; 11445d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang 11455d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang if (mDrmManagerClient == null) { 11465d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang mDrmManagerClient = new DrmManagerClient(mContext); 11475d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang } 11485d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang 11495d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang if (mDrmManagerClient.canHandle(path, null)) { 115059c14048bfc0a210077192410afa28ed6f85daa0Erik Almqvist mIsDrm = true; 11515d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang String drmMimetype = mDrmManagerClient.getOriginalMimeType(path); 11525d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang if (drmMimetype != null) { 11535d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang mMimeType = drmMimetype; 11545d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang resultFileType = MediaFile.getFileTypeForMimeType(drmMimetype); 11555d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang } 11565d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang } 11575d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang return resultFileType; 11585d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang } 11595d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang 11609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; // end of anonymous MediaScannerClient instance 116120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 116217d24400906235a172fc760e98656589692f798aJean-Michel Trivi private static boolean isSystemSoundWithMetadata(String path) { 116317d24400906235a172fc760e98656589692f798aJean-Michel Trivi if (path.startsWith(SYSTEM_SOUNDS_DIR + ALARMS_DIR) 116417d24400906235a172fc760e98656589692f798aJean-Michel Trivi || path.startsWith(SYSTEM_SOUNDS_DIR + RINGTONES_DIR) 1165c31033f43c85a07ebc6045c9b5af5408d0b306e9Jaekyun Seok || path.startsWith(SYSTEM_SOUNDS_DIR + NOTIFICATIONS_DIR) 1166c31033f43c85a07ebc6045c9b5af5408d0b306e9Jaekyun Seok || path.startsWith(PRODUCT_SOUNDS_DIR + ALARMS_DIR) 1167c31033f43c85a07ebc6045c9b5af5408d0b306e9Jaekyun Seok || path.startsWith(PRODUCT_SOUNDS_DIR + RINGTONES_DIR) 1168c31033f43c85a07ebc6045c9b5af5408d0b306e9Jaekyun Seok || path.startsWith(PRODUCT_SOUNDS_DIR + NOTIFICATIONS_DIR)) { 116917d24400906235a172fc760e98656589692f798aJean-Michel Trivi return true; 117017d24400906235a172fc760e98656589692f798aJean-Michel Trivi } 117117d24400906235a172fc760e98656589692f798aJean-Michel Trivi return false; 117217d24400906235a172fc760e98656589692f798aJean-Michel Trivi } 117317d24400906235a172fc760e98656589692f798aJean-Michel Trivi 117468528911b9f74475ac79c369a6482f720259dbacMarco Nelissen private String settingSetIndicatorName(String base) { 117568528911b9f74475ac79c369a6482f720259dbacMarco Nelissen return base + "_set"; 117668528911b9f74475ac79c369a6482f720259dbacMarco Nelissen } 117768528911b9f74475ac79c369a6482f720259dbacMarco Nelissen 11789dd3b2162dd308762a023ad07a39c2379bcbf931Jeff Sharkey private boolean wasRingtoneAlreadySet(String name) { 117968528911b9f74475ac79c369a6482f720259dbacMarco Nelissen ContentResolver cr = mContext.getContentResolver(); 118068528911b9f74475ac79c369a6482f720259dbacMarco Nelissen String indicatorName = settingSetIndicatorName(name); 118168528911b9f74475ac79c369a6482f720259dbacMarco Nelissen try { 118268528911b9f74475ac79c369a6482f720259dbacMarco Nelissen return Settings.System.getInt(cr, indicatorName) != 0; 118368528911b9f74475ac79c369a6482f720259dbacMarco Nelissen } catch (SettingNotFoundException e) { 118468528911b9f74475ac79c369a6482f720259dbacMarco Nelissen return false; 118568528911b9f74475ac79c369a6482f720259dbacMarco Nelissen } 118668528911b9f74475ac79c369a6482f720259dbacMarco Nelissen } 118768528911b9f74475ac79c369a6482f720259dbacMarco Nelissen 1188c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood private void prescan(String filePath, boolean prescanFiles) throws RemoteException { 11899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Cursor c = null; 11909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String where = null; 11919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String[] selectionArgs = null; 119220b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 119360cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey mPlayLists.clear(); 119420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 1195c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood if (filePath != null) { 1196c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood // query for only one file 119758ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen where = MediaStore.Files.FileColumns._ID + ">?" + 119858ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen " AND " + Files.FileColumns.DATA + "=?"; 119958ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen selectionArgs = new String[] { "", filePath }; 120058ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen } else { 120158ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen where = MediaStore.Files.FileColumns._ID + ">?"; 120258ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen selectionArgs = new String[] { "" }; 1203c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood } 1204c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood 12059dd3b2162dd308762a023ad07a39c2379bcbf931Jeff Sharkey mDefaultRingtoneSet = wasRingtoneAlreadySet(Settings.System.RINGTONE); 12069dd3b2162dd308762a023ad07a39c2379bcbf931Jeff Sharkey mDefaultNotificationSet = wasRingtoneAlreadySet(Settings.System.NOTIFICATION_SOUND); 12079dd3b2162dd308762a023ad07a39c2379bcbf931Jeff Sharkey mDefaultAlarmSet = wasRingtoneAlreadySet(Settings.System.ALARM_ALERT); 120868528911b9f74475ac79c369a6482f720259dbacMarco Nelissen 120958ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen // Tell the provider to not delete the file. 121058ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen // If the file is truly gone the delete is unnecessary, and we want to avoid 121158ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen // accidentally deleting files that are really there (this may happen if the 121258ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen // filesystem is mounted and unmounted while the scanner is running). 121358ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen Uri.Builder builder = mFilesUri.buildUpon(); 121458ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen builder.appendQueryParameter(MediaStore.PARAM_DELETE_DATA, "false"); 121560cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey MediaBulkDeleter deleter = new MediaBulkDeleter(mMediaProvider, builder.build()); 121658ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen 12179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Build the list of files from the content provider 12189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 1219c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood if (prescanFiles) { 122058ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen // First read existing files from the files table. 122158ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen // Because we'll be deleting entries for missing files as we go, 122258ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen // we need to query the database in small batches, to avoid problems 122358ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen // with CursorWindow positioning. 122458ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen long lastId = Long.MIN_VALUE; 122558ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen Uri limitUri = mFilesUri.buildUpon().appendQueryParameter("limit", "1000").build(); 122658ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen 122758ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen while (true) { 122858ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen selectionArgs[0] = "" + lastId; 122958ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen if (c != null) { 123058ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen c.close(); 123158ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen c = null; 123258ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen } 123360cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey c = mMediaProvider.query(limitUri, FILES_PRESCAN_PROJECTION, 123458ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen where, selectionArgs, MediaStore.Files.FileColumns._ID, null); 123558ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen if (c == null) { 123658ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen break; 123758ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen } 123820b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 123958ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen int num = c.getCount(); 1240c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood 124158ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen if (num == 0) { 124258ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen break; 124358ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen } 12449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (c.moveToNext()) { 1245d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood long rowId = c.getLong(FILES_PRESCAN_ID_COLUMN_INDEX); 1246d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood String path = c.getString(FILES_PRESCAN_PATH_COLUMN_INDEX); 1247d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood int format = c.getInt(FILES_PRESCAN_FORMAT_COLUMN_INDEX); 1248d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood long lastModified = c.getLong(FILES_PRESCAN_DATE_MODIFIED_COLUMN_INDEX); 124958ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen lastId = rowId; 125020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 125135b002a9c873fb40116179c8626b9841b0abae74Marco Nelissen // Only consider entries with absolute path names. 125235b002a9c873fb40116179c8626b9841b0abae74Marco Nelissen // This allows storing URIs in the database without the 125335b002a9c873fb40116179c8626b9841b0abae74Marco Nelissen // media scanner removing them. 12543e5e8055942ee8179675b8ed11d40ca12dbe42e6Marco Nelissen if (path != null && path.startsWith("/")) { 125558ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen boolean exists = false; 125658ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen try { 125734385d352da19805ae948215e2edbeedd16b7941Elliott Hughes exists = Os.access(path, android.system.OsConstants.F_OK); 125858ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen } catch (ErrnoException e1) { 125958ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen } 126058ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen if (!exists && !MtpConstants.isAbstractObject(format)) { 126158ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen // do not delete missing playlists, since they may have been 126258ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen // modified by the user. 126358ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen // The user can delete them in the media player instead. 126458ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen // instead, clear the path and lastModified fields in the row 126558ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen MediaFile.MediaFileType mediaFileType = MediaFile.getFileType(path); 126658ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen int fileType = (mediaFileType == null ? 0 : mediaFileType.fileType); 126758ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen 126858ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen if (!MediaFile.isPlayListFileType(fileType)) { 126958ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen deleter.delete(rowId); 127058ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen if (path.toLowerCase(Locale.US).endsWith("/.nomedia")) { 127158ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen deleter.flush(); 127258ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen String parent = new File(path).getParent(); 127360cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey mMediaProvider.call(MediaStore.UNHIDE_CALL, parent, null); 127458ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen } 127558ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen } 127635b002a9c873fb40116179c8626b9841b0abae74Marco Nelissen } 12779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project finally { 12839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (c != null) { 12849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project c.close(); 12859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 128658ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen deleter.flush(); 12879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12886458935331ccfacb4cccc50d6b893947febae687Mike Lockwood 12896458935331ccfacb4cccc50d6b893947febae687Mike Lockwood // compute original size of images 12906458935331ccfacb4cccc50d6b893947febae687Mike Lockwood mOriginalCount = 0; 129160cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey c = mMediaProvider.query(mImagesUri, ID_PROJECTION, null, null, null, null); 12926458935331ccfacb4cccc50d6b893947febae687Mike Lockwood if (c != null) { 12936458935331ccfacb4cccc50d6b893947febae687Mike Lockwood mOriginalCount = c.getCount(); 12946458935331ccfacb4cccc50d6b893947febae687Mike Lockwood c.close(); 12956458935331ccfacb4cccc50d6b893947febae687Mike Lockwood } 12969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 129720b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 12989ff4774cac499a376a59373d5bfb5112c9a2a004Marco Nelissen static class MediaBulkDeleter { 1299d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen StringBuilder whereClause = new StringBuilder(); 1300872e7b7073fad8295e6314c73b87d7cb3f85d39cRay Chen ArrayList<String> whereArgs = new ArrayList<String>(100); 130160cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey final ContentProviderClient mProvider; 130235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn final Uri mBaseUri; 13039ff4774cac499a376a59373d5bfb5112c9a2a004Marco Nelissen 130460cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey public MediaBulkDeleter(ContentProviderClient provider, Uri baseUri) { 13059ff4774cac499a376a59373d5bfb5112c9a2a004Marco Nelissen mProvider = provider; 13069ff4774cac499a376a59373d5bfb5112c9a2a004Marco Nelissen mBaseUri = baseUri; 13079ff4774cac499a376a59373d5bfb5112c9a2a004Marco Nelissen } 13089ff4774cac499a376a59373d5bfb5112c9a2a004Marco Nelissen 13099ff4774cac499a376a59373d5bfb5112c9a2a004Marco Nelissen public void delete(long id) throws RemoteException { 1310d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen if (whereClause.length() != 0) { 1311d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen whereClause.append(","); 13129ff4774cac499a376a59373d5bfb5112c9a2a004Marco Nelissen } 1313d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen whereClause.append("?"); 1314d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen whereArgs.add("" + id); 1315d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen if (whereArgs.size() > 100) { 13169ff4774cac499a376a59373d5bfb5112c9a2a004Marco Nelissen flush(); 13179ff4774cac499a376a59373d5bfb5112c9a2a004Marco Nelissen } 13189ff4774cac499a376a59373d5bfb5112c9a2a004Marco Nelissen } 13199ff4774cac499a376a59373d5bfb5112c9a2a004Marco Nelissen public void flush() throws RemoteException { 1320d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen int size = whereArgs.size(); 1321d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen if (size > 0) { 1322d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen String [] foo = new String [size]; 1323d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen foo = whereArgs.toArray(foo); 132460cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey int numrows = mProvider.delete(mBaseUri, 132535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn MediaStore.MediaColumns._ID + " IN (" + 1326d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen whereClause.toString() + ")", foo); 1327d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen //Log.i("@@@@@@@@@", "rows deleted: " + numrows); 1328d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen whereClause.setLength(0); 1329d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen whereArgs.clear(); 1330d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen } 13319ff4774cac499a376a59373d5bfb5112c9a2a004Marco Nelissen } 13329ff4774cac499a376a59373d5bfb5112c9a2a004Marco Nelissen } 13339ff4774cac499a376a59373d5bfb5112c9a2a004Marco Nelissen 133468528911b9f74475ac79c369a6482f720259dbacMarco Nelissen private void postscan(final String[] directories) throws RemoteException { 133520b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 13369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // handle playlists last, after we know what media files are on the storage. 13379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mProcessPlaylists) { 13389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project processPlayLists(); 13399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 134020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 13419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // allow GC to clean up 134260cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey mPlayLists.clear(); 13439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 134420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 13451b37c3bddcdfe7cb60e776e3eb05bfbb46b0b282Mattias Nilsson private void releaseResources() { 13461b37c3bddcdfe7cb60e776e3eb05bfbb46b0b282Mattias Nilsson // release the DrmManagerClient resources 13471b37c3bddcdfe7cb60e776e3eb05bfbb46b0b282Mattias Nilsson if (mDrmManagerClient != null) { 134860cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey mDrmManagerClient.close(); 13491b37c3bddcdfe7cb60e776e3eb05bfbb46b0b282Mattias Nilsson mDrmManagerClient = null; 13501b37c3bddcdfe7cb60e776e3eb05bfbb46b0b282Mattias Nilsson } 13511b37c3bddcdfe7cb60e776e3eb05bfbb46b0b282Mattias Nilsson } 13521b37c3bddcdfe7cb60e776e3eb05bfbb46b0b282Mattias Nilsson 135360cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey public void scanDirectories(String[] directories) { 13549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 13559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long start = System.currentTimeMillis(); 1356c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood prescan(null, true); 13579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long prescan = System.currentTimeMillis(); 1358e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood 13593410b4656505673c72da558dcfec94d7b135e760Mike Lockwood if (ENABLE_BULK_INSERTS) { 13608e2ed8d512ade2ea481b3a292556782b17a74674Dongwon Kang // create MediaInserter for bulk inserts 136160cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey mMediaInserter = new MediaInserter(mMediaProvider, 500); 13623410b4656505673c72da558dcfec94d7b135e760Mike Lockwood } 136320b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 13649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < directories.length; i++) { 1365c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood processDirectory(directories[i], mClient); 13669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1367e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood 13683410b4656505673c72da558dcfec94d7b135e760Mike Lockwood if (ENABLE_BULK_INSERTS) { 13693410b4656505673c72da558dcfec94d7b135e760Mike Lockwood // flush remaining inserts 13708e2ed8d512ade2ea481b3a292556782b17a74674Dongwon Kang mMediaInserter.flushAll(); 13718e2ed8d512ade2ea481b3a292556782b17a74674Dongwon Kang mMediaInserter = null; 13723410b4656505673c72da558dcfec94d7b135e760Mike Lockwood } 1373bd682b040833fce9e212c00c395b32bec7050f87Mike Lockwood 13749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long scan = System.currentTimeMillis(); 13759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project postscan(directories); 13769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long end = System.currentTimeMillis(); 137720b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 137843a17654cf4bfe7f1ec22bd8b7b32daccdf27c09Joe Onorato if (false) { 13799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.d(TAG, " prescan time: " + (prescan - start) + "ms\n"); 13809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.d(TAG, " scan time: " + (scan - prescan) + "ms\n"); 13819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.d(TAG, "postscan time: " + (end - scan) + "ms\n"); 13829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.d(TAG, " total time: " + (end - start) + "ms\n"); 13839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (SQLException e) { 13859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // this might happen if the SD card is removed while the media scanner is running 13869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "SQLException in MediaScanner.scan()", e); 13879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (UnsupportedOperationException e) { 13889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // this might happen if the SD card is removed while the media scanner is running 13899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "UnsupportedOperationException in MediaScanner.scan()", e); 13909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (RemoteException e) { 13919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "RemoteException in MediaScanner.scan()", e); 13921b37c3bddcdfe7cb60e776e3eb05bfbb46b0b282Mattias Nilsson } finally { 13931b37c3bddcdfe7cb60e776e3eb05bfbb46b0b282Mattias Nilsson releaseResources(); 13949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // this function is used to scan a single file 139860cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey public Uri scanSingleFile(String path, String mimeType) { 13999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 1400c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood prescan(path, true); 140120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 14029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project File file = new File(path); 14036124cddc629eb0a13e9d9e30e0613614d17950c5Bartosz Bialek if (!file.exists() || !file.canRead()) { 1404348aa65e93c1b8cb409de12e3e61136f894201f2Marco Nelissen return null; 1405348aa65e93c1b8cb409de12e3e61136f894201f2Marco Nelissen } 1406ec74abb71f79cdc573c536115acc7ff26a02680aMikael 1407ec74abb71f79cdc573c536115acc7ff26a02680aMikael // lastModified is in milliseconds on Files. 1408ec74abb71f79cdc573c536115acc7ff26a02680aMikael long lastModifiedSeconds = file.lastModified() / 1000; 1409ec74abb71f79cdc573c536115acc7ff26a02680aMikael 14109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // always scan the file, so we can return the content://media Uri for existing files 14117a0bd17bceaf3efc3732e30c538fae420d3b742cMike Lockwood return mClient.doScanFile(path, mimeType, lastModifiedSeconds, file.length(), 141266dfcd465c02d78cb4ff22e7b509ee42d4309286Marco Nelissen false, true, MediaScanner.isNoMediaPath(path)); 14139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (RemoteException e) { 14149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "RemoteException in MediaScanner.scanFile()", e); 14159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 14161b37c3bddcdfe7cb60e776e3eb05bfbb46b0b282Mattias Nilsson } finally { 14171b37c3bddcdfe7cb60e776e3eb05bfbb46b0b282Mattias Nilsson releaseResources(); 14189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1421ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood private static boolean isNoMediaFile(String path) { 1422ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood File file = new File(path); 1423ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood if (file.isDirectory()) return false; 1424ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood 1425ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood // special case certain file names 1426ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood // I use regionMatches() instead of substring() below 1427ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood // to avoid memory allocation 1428ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood int lastSlash = path.lastIndexOf('/'); 1429ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood if (lastSlash >= 0 && lastSlash + 2 < path.length()) { 1430ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood // ignore those ._* files created by MacOS 1431ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood if (path.regionMatches(lastSlash + 1, "._", 0, 2)) { 1432ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood return true; 1433ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood } 1434ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood 1435ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood // ignore album art files created by Windows Media Player: 1436ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood // Folder.jpg, AlbumArtSmall.jpg, AlbumArt_{...}_Large.jpg 1437ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood // and AlbumArt_{...}_Small.jpg 1438ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood if (path.regionMatches(true, path.length() - 4, ".jpg", 0, 4)) { 1439ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood if (path.regionMatches(true, lastSlash + 1, "AlbumArt_{", 0, 10) || 1440ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood path.regionMatches(true, lastSlash + 1, "AlbumArt.", 0, 9)) { 1441ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood return true; 1442ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood } 1443ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood int length = path.length() - lastSlash - 1; 1444ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood if ((length == 17 && path.regionMatches( 1445ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood true, lastSlash + 1, "AlbumArtSmall", 0, 13)) || 1446ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood (length == 10 1447ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood && path.regionMatches(true, lastSlash + 1, "Folder", 0, 6))) { 1448ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood return true; 1449ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood } 1450ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood } 1451ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood } 1452ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood return false; 1453ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood } 1454ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood 145593a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen private static HashMap<String,String> mNoMediaPaths = new HashMap<String,String>(); 145693a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen private static HashMap<String,String> mMediaPaths = new HashMap<String,String>(); 1457997354e4b4a9666cedd62282471e97822affced9Mike Lockwood 145893a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen /* MediaProvider calls this when a .nomedia file is added or removed */ 145993a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen public static void clearMediaPathCache(boolean clearMediaPaths, boolean clearNoMediaPaths) { 146093a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen synchronized (MediaScanner.class) { 146193a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen if (clearMediaPaths) { 146293a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen mMediaPaths.clear(); 146393a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen } 146493a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen if (clearNoMediaPaths) { 146593a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen mNoMediaPaths.clear(); 146693a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen } 146793a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen } 146893a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen } 146993a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen 147093a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen public static boolean isNoMediaPath(String path) { 147193a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen if (path == null) { 147293a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen return false; 147393a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen } 1474997354e4b4a9666cedd62282471e97822affced9Mike Lockwood // return true if file or any parent directory has name starting with a dot 147593a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen if (path.indexOf("/.") >= 0) { 147693a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen return true; 147793a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen } 147893a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen 147993a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen int firstSlash = path.lastIndexOf('/'); 1480d5a579765e06d69c1a33663c202c3593a5bd5c6bMarco Nelissen if (firstSlash <= 0) { 148193a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen return false; 148293a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen } 148393a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen String parent = path.substring(0, firstSlash); 148493a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen 148593a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen synchronized (MediaScanner.class) { 148693a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen if (mNoMediaPaths.containsKey(parent)) { 148793a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen return true; 148893a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen } else if (!mMediaPaths.containsKey(parent)) { 148993a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen // check to see if any parent directories have a ".nomedia" file 149093a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen // start from 1 so we don't bother checking in the root directory 149193a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen int offset = 1; 149293a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen while (offset >= 0) { 149393a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen int slashIndex = path.indexOf('/', offset); 149493a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen if (slashIndex > offset) { 149593a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen slashIndex++; // move past slash 149693a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen File file = new File(path.substring(0, slashIndex) + ".nomedia"); 149793a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen if (file.exists()) { 149893a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen // we have a .nomedia in one of the parent directories 149993a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen mNoMediaPaths.put(parent, ""); 150093a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen return true; 150193a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen } 150293a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen } 150393a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen offset = slashIndex; 1504997354e4b4a9666cedd62282471e97822affced9Mike Lockwood } 150593a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen mMediaPaths.put(parent, ""); 1506997354e4b4a9666cedd62282471e97822affced9Mike Lockwood } 1507997354e4b4a9666cedd62282471e97822affced9Mike Lockwood } 150893a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen 1509ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood return isNoMediaFile(path); 1510997354e4b4a9666cedd62282471e97822affced9Mike Lockwood } 1511997354e4b4a9666cedd62282471e97822affced9Mike Lockwood 151260cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey public void scanMtpFile(String path, int objectHandle, int format) { 1513c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood MediaFile.MediaFileType mediaFileType = MediaFile.getFileType(path); 1514c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood int fileType = (mediaFileType == null ? 0 : mediaFileType.fileType); 15157a0bd17bceaf3efc3732e30c538fae420d3b742cMike Lockwood File file = new File(path); 15167a0bd17bceaf3efc3732e30c538fae420d3b742cMike Lockwood long lastModifiedSeconds = file.lastModified() / 1000; 1517c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood 1518c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood if (!MediaFile.isAudioFileType(fileType) && !MediaFile.isVideoFileType(fileType) && 151920c38ea9fd4024cc076c825f46cdfb34ffc090deJan Bjernler !MediaFile.isImageFileType(fileType) && !MediaFile.isPlayListFileType(fileType) && 152020c38ea9fd4024cc076c825f46cdfb34ffc090deJan Bjernler !MediaFile.isDrmFileType(fileType)) { 15217a0bd17bceaf3efc3732e30c538fae420d3b742cMike Lockwood 15227a0bd17bceaf3efc3732e30c538fae420d3b742cMike Lockwood // no need to use the media scanner, but we need to update last modified and file size 15237a0bd17bceaf3efc3732e30c538fae420d3b742cMike Lockwood ContentValues values = new ContentValues(); 15247a0bd17bceaf3efc3732e30c538fae420d3b742cMike Lockwood values.put(Files.FileColumns.SIZE, file.length()); 15257a0bd17bceaf3efc3732e30c538fae420d3b742cMike Lockwood values.put(Files.FileColumns.DATE_MODIFIED, lastModifiedSeconds); 15267a0bd17bceaf3efc3732e30c538fae420d3b742cMike Lockwood try { 15277a0bd17bceaf3efc3732e30c538fae420d3b742cMike Lockwood String[] whereArgs = new String[] { Integer.toString(objectHandle) }; 152860cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey mMediaProvider.update(Files.getMtpObjectsUri(mVolumeName), values, 152935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn "_id=?", whereArgs); 15307a0bd17bceaf3efc3732e30c538fae420d3b742cMike Lockwood } catch (RemoteException e) { 15317a0bd17bceaf3efc3732e30c538fae420d3b742cMike Lockwood Log.e(TAG, "RemoteException in scanMtpFile", e); 15327a0bd17bceaf3efc3732e30c538fae420d3b742cMike Lockwood } 1533c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood return; 1534c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood } 1535c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood 1536d815f79766984fce499e147ecbacc01914683f74Mike Lockwood mMtpObjectHandle = objectHandle; 1537c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen Cursor fileList = null; 1538c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood try { 1539caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood if (MediaFile.isPlayListFileType(fileType)) { 1540caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood // build file cache so we can look up tracks in the playlist 1541caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood prescan(null, true); 1542caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood 154358ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen FileEntry entry = makeEntryFor(path); 1544caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood if (entry != null) { 154560cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey fileList = mMediaProvider.query(mFilesUri, 154635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn FILES_PRESCAN_PROJECTION, null, null, null, null); 1547c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen processPlayList(entry, fileList); 1548caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood } 1549caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood } else { 1550caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood // MTP will create a file entry for us so we don't want to do it in prescan 1551caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood prescan(path, false); 1552c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood 1553caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood // always scan the file, so we can return the content://media Uri for existing files 1554076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood mClient.doScanFile(path, mediaFileType.mimeType, lastModifiedSeconds, file.length(), 1555997354e4b4a9666cedd62282471e97822affced9Mike Lockwood (format == MtpConstants.FORMAT_ASSOCIATION), true, isNoMediaPath(path)); 1556caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood } 1557c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood } catch (RemoteException e) { 1558c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood Log.e(TAG, "RemoteException in MediaScanner.scanFile()", e); 1559c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood } finally { 1560c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood mMtpObjectHandle = 0; 1561c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen if (fileList != null) { 1562c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen fileList.close(); 1563c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen } 15641b37c3bddcdfe7cb60e776e3eb05bfbb46b0b282Mattias Nilsson releaseResources(); 1565c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood } 1566d815f79766984fce499e147ecbacc01914683f74Mike Lockwood } 1567d815f79766984fce499e147ecbacc01914683f74Mike Lockwood 156858ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen FileEntry makeEntryFor(String path) { 156958ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen String where; 157058ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen String[] selectionArgs; 157158ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen 157258ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen Cursor c = null; 157358ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen try { 1574da8fe0faf5b52ef65bd07b6f47479ac537d42d47Marco Nelissen where = Files.FileColumns.DATA + "=?"; 1575da8fe0faf5b52ef65bd07b6f47479ac537d42d47Marco Nelissen selectionArgs = new String[] { path }; 157660cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey c = mMediaProvider.query(mFilesUriNoNotify, FILES_PRESCAN_PROJECTION, 157758ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen where, selectionArgs, null, null); 15788ab2dc2f9680307febe997631c2148729f714e3dMarco Nelissen if (c.moveToFirst()) { 157958ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen long rowId = c.getLong(FILES_PRESCAN_ID_COLUMN_INDEX); 158058ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen int format = c.getInt(FILES_PRESCAN_FORMAT_COLUMN_INDEX); 158158ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen long lastModified = c.getLong(FILES_PRESCAN_DATE_MODIFIED_COLUMN_INDEX); 158258ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen return new FileEntry(rowId, path, lastModified, format); 158358ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen } 158458ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen } catch (RemoteException e) { 158558ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen } finally { 158658ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen if (c != null) { 158758ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen c.close(); 158858ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen } 158958ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen } 159058ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen return null; 159158ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen } 159258ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen 15939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // returns the number of matching file/directory names, starting from the right 15949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int matchPaths(String path1, String path2) { 15959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int result = 0; 15969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int end1 = path1.length(); 15979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int end2 = path2.length(); 159820b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 15999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (end1 > 0 && end2 > 0) { 16009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int slash1 = path1.lastIndexOf('/', end1 - 1); 16019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int slash2 = path2.lastIndexOf('/', end2 - 1); 16029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int backSlash1 = path1.lastIndexOf('\\', end1 - 1); 16039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int backSlash2 = path2.lastIndexOf('\\', end2 - 1); 16049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int start1 = (slash1 > backSlash1 ? slash1 : backSlash1); 16059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int start2 = (slash2 > backSlash2 ? slash2 : backSlash2); 16069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (start1 < 0) start1 = 0; else start1++; 16079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (start2 < 0) start2 = 0; else start2++; 16089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int length = end1 - start1; 16099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (end2 - start2 != length) break; 16109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (path1.regionMatches(true, start1, path2, start2, length)) { 16119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project result++; 16129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project end1 = start1 - 1; 16139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project end2 = start2 - 1; 16149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else break; 16159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 161620b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 16179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return result; 16189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16200b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen private boolean matchEntries(long rowId, String data) { 16210b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen 16220b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen int len = mPlaylistEntries.size(); 16230b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen boolean done = true; 16240b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen for (int i = 0; i < len; i++) { 16250b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen PlaylistEntry entry = mPlaylistEntries.get(i); 16260b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen if (entry.bestmatchlevel == Integer.MAX_VALUE) { 16270b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen continue; // this entry has been matched already 16280b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen } 16290b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen done = false; 16300b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen if (data.equalsIgnoreCase(entry.path)) { 16310b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen entry.bestmatchid = rowId; 16320b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen entry.bestmatchlevel = Integer.MAX_VALUE; 16330b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen continue; // no need for path matching 16340b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen } 16350b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen 16360b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen int matchLength = matchPaths(data, entry.path); 16370b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen if (matchLength > entry.bestmatchlevel) { 16380b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen entry.bestmatchid = rowId; 16390b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen entry.bestmatchlevel = matchLength; 16400b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen } 16410b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen } 16420b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen return done; 16430b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen } 164420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 16450b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen private void cachePlaylistEntry(String line, String playListDirectory) { 16460b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen PlaylistEntry entry = new PlaylistEntry(); 16479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // watch for trailing whitespace 16480b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen int entryLength = line.length(); 16490b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen while (entryLength > 0 && Character.isWhitespace(line.charAt(entryLength - 1))) entryLength--; 16509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // path should be longer than 3 characters. 16519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // avoid index out of bounds errors below by returning here. 16520b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen if (entryLength < 3) return; 16530b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen if (entryLength < line.length()) line = line.substring(0, entryLength); 16549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // does entry appear to be an absolute path? 16569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // look for Unix or DOS absolute paths 16570b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen char ch1 = line.charAt(0); 16589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean fullPath = (ch1 == '/' || 16590b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen (Character.isLetter(ch1) && line.charAt(1) == ':' && line.charAt(2) == '\\')); 16609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // if we have a relative path, combine entry with playListDirectory 16619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!fullPath) 16620b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen line = playListDirectory + line; 16630b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen entry.path = line; 16649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //FIXME - should we look for "../" within the path? 166520b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 16660b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen mPlaylistEntries.add(entry); 16670b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen } 166820b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 16690b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen private void processCachedPlaylist(Cursor fileList, ContentValues values, Uri playlistUri) { 16700b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen fileList.moveToPosition(-1); 16710b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen while (fileList.moveToNext()) { 16720b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen long rowId = fileList.getLong(FILES_PRESCAN_ID_COLUMN_INDEX); 16730b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen String data = fileList.getString(FILES_PRESCAN_PATH_COLUMN_INDEX); 16740b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen if (matchEntries(rowId, data)) { 16750b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen break; 16769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 167820b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 16790b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen int len = mPlaylistEntries.size(); 16800b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen int index = 0; 16810b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen for (int i = 0; i < len; i++) { 16820b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen PlaylistEntry entry = mPlaylistEntries.get(i); 16830b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen if (entry.bestmatchlevel > 0) { 16840b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen try { 16850b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen values.clear(); 16860b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen values.put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, Integer.valueOf(index)); 16870b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen values.put(MediaStore.Audio.Playlists.Members.AUDIO_ID, Long.valueOf(entry.bestmatchid)); 168860cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey mMediaProvider.insert(playlistUri, values); 16890b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen index++; 16900b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen } catch (RemoteException e) { 16910b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen Log.e(TAG, "RemoteException in MediaScanner.processCachedPlaylist()", e); 16920b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen return; 16937d92a22d9dec42a45cd55fd77d0a86b4b9c6e9dfDongwon Kang } 16947d92a22d9dec42a45cd55fd77d0a86b4b9c6e9dfDongwon Kang } 16959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16960b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen mPlaylistEntries.clear(); 16979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 169820b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 1699c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen private void processM3uPlayList(String path, String playListDirectory, Uri uri, 1700c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen ContentValues values, Cursor fileList) { 17019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project BufferedReader reader = null; 17029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 17039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project File f = new File(path); 17049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (f.exists()) { 17059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project reader = new BufferedReader( 17069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project new InputStreamReader(new FileInputStream(f)), 8192); 17079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String line = reader.readLine(); 17080b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen mPlaylistEntries.clear(); 17099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (line != null) { 17109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // ignore comment lines, which begin with '#' 17119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (line.length() > 0 && line.charAt(0) != '#') { 17120b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen cachePlaylistEntry(line, playListDirectory); 17139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project line = reader.readLine(); 17159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17160b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen 17170b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen processCachedPlaylist(fileList, values, uri); 17189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 17209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "IOException in MediaScanner.processM3uPlayList()", e); 17219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 17229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 17239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (reader != null) 17249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project reader.close(); 17259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 17269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "IOException in MediaScanner.processM3uPlayList()", e); 17279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1731c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen private void processPlsPlayList(String path, String playListDirectory, Uri uri, 1732c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen ContentValues values, Cursor fileList) { 17339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project BufferedReader reader = null; 17349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 17359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project File f = new File(path); 17369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (f.exists()) { 17379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project reader = new BufferedReader( 17389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project new InputStreamReader(new FileInputStream(f)), 8192); 17399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String line = reader.readLine(); 17400b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen mPlaylistEntries.clear(); 17419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (line != null) { 17429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // ignore comment lines, which begin with '#' 17439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (line.startsWith("File")) { 17449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int equals = line.indexOf('='); 17459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (equals > 0) { 1746538d4925b36067dc89ad0625a69dafeaa364bd2eMarco Nelissen cachePlaylistEntry(line.substring(equals + 1), playListDirectory); 17479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project line = reader.readLine(); 17509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17510b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen 17520b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen processCachedPlaylist(fileList, values, uri); 17539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 17559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "IOException in MediaScanner.processPlsPlayList()", e); 17569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 17579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 17589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (reader != null) 17599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project reader.close(); 17609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 17619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "IOException in MediaScanner.processPlsPlayList()", e); 17629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project class WplHandler implements ElementListener { 17679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final ContentHandler handler; 17699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String playListDirectory; 17709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1771c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen public WplHandler(String playListDirectory, Uri uri, Cursor fileList) { 17729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this.playListDirectory = playListDirectory; 177320b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 17749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project RootElement root = new RootElement("smil"); 17759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Element body = root.getChild("body"); 17769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Element seq = body.getChild("seq"); 17779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Element media = seq.getChild("media"); 17789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project media.setElementListener(this); 17799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this.handler = root.getContentHandler(); 17819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1783c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen @Override 17849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void start(Attributes attributes) { 17859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String path = attributes.getValue("", "src"); 17869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (path != null) { 17870b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen cachePlaylistEntry(path, playListDirectory); 17889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17910b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen @Override 17929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void end() { 17939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ContentHandler getContentHandler() { 17969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return handler; 17979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1800c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen private void processWplPlayList(String path, String playListDirectory, Uri uri, 18010b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen ContentValues values, Cursor fileList) { 18029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project FileInputStream fis = null; 18039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 18049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project File f = new File(path); 18059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (f.exists()) { 18069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fis = new FileInputStream(f); 18079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18080b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen mPlaylistEntries.clear(); 1809c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen Xml.parse(fis, Xml.findEncodingByName("UTF-8"), 1810c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen new WplHandler(playListDirectory, uri, fileList).getContentHandler()); 18110b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen 18120b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen processCachedPlaylist(fileList, values, uri); 18139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (SAXException e) { 18159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project e.printStackTrace(); 18169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 18179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project e.printStackTrace(); 18189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 18199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 18209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (fis != null) 18219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fis.close(); 18229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 18239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "IOException in MediaScanner.processWplPlayList()", e); 18249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 182720b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 1828c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen private void processPlayList(FileEntry entry, Cursor fileList) throws RemoteException { 1829caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood String path = entry.mPath; 1830caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood ContentValues values = new ContentValues(); 1831caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood int lastSlash = path.lastIndexOf('/'); 1832caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood if (lastSlash < 0) throw new IllegalArgumentException("bad path " + path); 1833caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood Uri uri, membersUri; 1834caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood long rowId = entry.mRowId; 1835caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood 1836242d0cdc1ad6c48faca403ea352bde73138443b5Mike Lockwood // make sure we have a name 1837242d0cdc1ad6c48faca403ea352bde73138443b5Mike Lockwood String name = values.getAsString(MediaStore.Audio.Playlists.NAME); 1838242d0cdc1ad6c48faca403ea352bde73138443b5Mike Lockwood if (name == null) { 1839242d0cdc1ad6c48faca403ea352bde73138443b5Mike Lockwood name = values.getAsString(MediaStore.MediaColumns.TITLE); 1840242d0cdc1ad6c48faca403ea352bde73138443b5Mike Lockwood if (name == null) { 1841242d0cdc1ad6c48faca403ea352bde73138443b5Mike Lockwood // extract name from file name 1842242d0cdc1ad6c48faca403ea352bde73138443b5Mike Lockwood int lastDot = path.lastIndexOf('.'); 1843242d0cdc1ad6c48faca403ea352bde73138443b5Mike Lockwood name = (lastDot < 0 ? path.substring(lastSlash + 1) 1844242d0cdc1ad6c48faca403ea352bde73138443b5Mike Lockwood : path.substring(lastSlash + 1, lastDot)); 1845242d0cdc1ad6c48faca403ea352bde73138443b5Mike Lockwood } 1846242d0cdc1ad6c48faca403ea352bde73138443b5Mike Lockwood } 1847242d0cdc1ad6c48faca403ea352bde73138443b5Mike Lockwood 1848242d0cdc1ad6c48faca403ea352bde73138443b5Mike Lockwood values.put(MediaStore.Audio.Playlists.NAME, name); 1849242d0cdc1ad6c48faca403ea352bde73138443b5Mike Lockwood values.put(MediaStore.Audio.Playlists.DATE_MODIFIED, entry.mLastModified); 1850242d0cdc1ad6c48faca403ea352bde73138443b5Mike Lockwood 1851242d0cdc1ad6c48faca403ea352bde73138443b5Mike Lockwood if (rowId == 0) { 1852caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood values.put(MediaStore.Audio.Playlists.DATA, path); 185360cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey uri = mMediaProvider.insert(mPlaylistsUri, values); 1854caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood rowId = ContentUris.parseId(uri); 1855caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood membersUri = Uri.withAppendedPath(uri, Playlists.Members.CONTENT_DIRECTORY); 1856caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood } else { 1857caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood uri = ContentUris.withAppendedId(mPlaylistsUri, rowId); 185860cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey mMediaProvider.update(uri, values, null, null); 185920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 1860caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood // delete members of existing playlist 1861caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood membersUri = Uri.withAppendedPath(uri, Playlists.Members.CONTENT_DIRECTORY); 186260cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey mMediaProvider.delete(membersUri, null, null); 1863caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood } 18649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1865caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood String playListDirectory = path.substring(0, lastSlash + 1); 1866caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood MediaFile.MediaFileType mediaFileType = MediaFile.getFileType(path); 1867caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood int fileType = (mediaFileType == null ? 0 : mediaFileType.fileType); 186820b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 1869caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood if (fileType == MediaFile.FILE_TYPE_M3U) { 1870c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen processM3uPlayList(path, playListDirectory, membersUri, values, fileList); 1871caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood } else if (fileType == MediaFile.FILE_TYPE_PLS) { 1872c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen processPlsPlayList(path, playListDirectory, membersUri, values, fileList); 1873caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood } else if (fileType == MediaFile.FILE_TYPE_WPL) { 18740b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen processWplPlayList(path, playListDirectory, membersUri, values, fileList); 1875caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood } 1876caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood } 187720b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 1878caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood private void processPlayLists() throws RemoteException { 187958ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen Iterator<FileEntry> iterator = mPlayLists.iterator(); 1880c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen Cursor fileList = null; 1881c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen try { 188208f70fa5b82faa00d4d536b5a220d7ce8dd8f932Marco Nelissen // use the files uri and projection because we need the format column, 188308f70fa5b82faa00d4d536b5a220d7ce8dd8f932Marco Nelissen // but restrict the query to just audio files 188460cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey fileList = mMediaProvider.query(mFilesUri, FILES_PRESCAN_PROJECTION, 188508f70fa5b82faa00d4d536b5a220d7ce8dd8f932Marco Nelissen "media_type=2", null, null, null); 1886c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen while (iterator.hasNext()) { 1887c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen FileEntry entry = iterator.next(); 1888c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen // only process playlist files if they are new or have been modified since the last scan 1889c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen if (entry.mLastModifiedChanged) { 1890c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen processPlayList(entry, fileList); 1891c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen } 1892c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen } 1893c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen } catch (RemoteException e1) { 1894c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen } finally { 1895c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen if (fileList != null) { 1896c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen fileList.close(); 18979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 190020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 1901c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood private native void processDirectory(String path, MediaScannerClient client); 1902bab75909fac9c65b71012f4c06302503c2f72be1Marco Nelissen private native boolean processFile(String path, String mimeType, MediaScannerClient client); 190360cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey private native void setLocale(String locale); 190420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 19059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public native byte[] extractAlbumArt(FileDescriptor fd); 19069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 19074935d05eaa306cef88cf0ab13eca386f270409ecMarco Nelissen private static native final void native_init(); 19089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private native final void native_setup(); 19099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private native final void native_finalize(); 1910133cf8b92a07d5be8c64607b9644aa9cef169fb0James Dong 191160cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey @Override 191260cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey public void close() { 191360cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey mCloseGuard.close(); 191460cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey if (mClosed.compareAndSet(false, true)) { 191560cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey mMediaProvider.close(); 191660cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey native_finalize(); 191760cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey } 1918133cf8b92a07d5be8c64607b9644aa9cef169fb0James Dong } 1919133cf8b92a07d5be8c64607b9644aa9cef169fb0James Dong 19209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 192160cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey protected void finalize() throws Throwable { 192260cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey try { 1923492e9e851cadca62df84eaff1a3c1ba788492fbaNarayan Kamath if (mCloseGuard != null) { 1924492e9e851cadca62df84eaff1a3c1ba788492fbaNarayan Kamath mCloseGuard.warnIfOpen(); 1925492e9e851cadca62df84eaff1a3c1ba788492fbaNarayan Kamath } 1926492e9e851cadca62df84eaff1a3c1ba788492fbaNarayan Kamath 192760cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey close(); 192860cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey } finally { 192960cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey super.finalize(); 193060cfad80bdf61db436643927337c2fb30186e99dJeff Sharkey } 19319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 19329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1933