MediaScanner.java revision 250528e5b2362cb7b6749afb331acd8226f67744
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License. 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.media; 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 19bfcb22a207499c7ecd4aef9bea2ac778d8be8fc8Marco Nelissenimport org.xml.sax.Attributes; 20bfcb22a207499c7ecd4aef9bea2ac778d8be8fc8Marco Nelissenimport org.xml.sax.ContentHandler; 21bfcb22a207499c7ecd4aef9bea2ac778d8be8fc8Marco Nelissenimport org.xml.sax.SAXException; 22bfcb22a207499c7ecd4aef9bea2ac778d8be8fc8Marco Nelissen 23bfcb22a207499c7ecd4aef9bea2ac778d8be8fc8Marco Nelissenimport android.content.ContentUris; 249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ContentValues; 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context; 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.IContentProvider; 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.database.Cursor; 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.database.SQLException; 295d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wangimport android.drm.DrmManagerClient; 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.BitmapFactory; 319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.Uri; 32250528e5b2362cb7b6749afb331acd8226f67744Mike Lockwoodimport android.os.Environment; 339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Process; 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.RemoteException; 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemProperties; 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.MediaStore; 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.Settings; 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.MediaStore.Audio; 39c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwoodimport android.provider.MediaStore.Files; 409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.MediaStore.Images; 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.MediaStore.Video; 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.MediaStore.Audio.Genres; 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.MediaStore.Audio.Playlists; 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.sax.Element; 459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.sax.ElementListener; 469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.sax.RootElement; 479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.TextUtils; 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Config; 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log; 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Xml; 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 52bfcb22a207499c7ecd4aef9bea2ac778d8be8fc8Marco Nelissenimport java.io.BufferedReader; 53bfcb22a207499c7ecd4aef9bea2ac778d8be8fc8Marco Nelissenimport java.io.File; 54bfcb22a207499c7ecd4aef9bea2ac778d8be8fc8Marco Nelissenimport java.io.FileDescriptor; 55bfcb22a207499c7ecd4aef9bea2ac778d8be8fc8Marco Nelissenimport java.io.FileInputStream; 56bfcb22a207499c7ecd4aef9bea2ac778d8be8fc8Marco Nelissenimport java.io.IOException; 57bfcb22a207499c7ecd4aef9bea2ac778d8be8fc8Marco Nelissenimport java.io.InputStreamReader; 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList; 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.HashMap; 609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.HashSet; 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Iterator; 629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 6477f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * Internal service helper that no-one should use directly. 6520b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync * 6677f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * The way the scan currently works is: 6777f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * - The Java MediaScannerService creates a MediaScanner (this class), and calls 6877f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * MediaScanner.scanDirectories on it. 6977f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * - scanDirectories() calls the native processDirectory() for each of the specified directories. 7077f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * - the processDirectory() JNI method wraps the provided mediascanner client in a native 7177f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * 'MyMediaScannerClient' class, then calls processDirectory() on the native MediaScanner 7277f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * object (which got created when the Java MediaScanner was created). 7377f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * - native MediaScanner.processDirectory() (currently part of opencore) calls 7477f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * doProcessDirectory(), which recurses over the folder, and calls 7577f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * native MyMediaScannerClient.scanFile() for every file whose extension matches. 7677f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * - native MyMediaScannerClient.scanFile() calls back on Java MediaScannerClient.scanFile, 7777f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * which calls doScanFile, which after some setup calls back down to native code, calling 7877f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * MediaScanner.processFile(). 7977f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * - MediaScanner.processFile() calls one of several methods, depending on the type of the 8077f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * file: parseMP3, parseMP4, parseMidi, parseOgg or parseWMA. 8177f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * - each of these methods gets metadata key/value pairs from the file, and repeatedly 8277f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * calls native MyMediaScannerClient.handleStringTag, which calls back up to its Java 8377f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * counterparts in this file. 8477f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * - Java handleStringTag() gathers the key/value pairs that it's interested in. 8577f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * - once processFile returns and we're back in Java code in doScanFile(), it calls 8677f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * Java MyMediaScannerClient.endFile(), which takes all the data that's been 8777f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * gathered and inserts an entry in to the database. 8877f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * 8977f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * In summary: 9077f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * Java MediaScannerService calls 9177f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * Java MediaScanner scanDirectories, which calls 9277f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * Java MediaScanner processDirectory (native method), which calls 9377f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * native MediaScanner processDirectory, which calls 9477f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * native MyMediaScannerClient scanFile, which calls 9577f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * Java MyMediaScannerClient scanFile, which calls 9677f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * Java MediaScannerClient doScanFile, which calls 9777f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * Java MediaScanner processFile (native method), which calls 9877f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * native MediaScanner processFile, which calls 9977f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * native parseMP3, parseMP4, parseMidi, parseOgg or parseWMA, which calls 10077f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * native MyMediaScanner handleStringTag, which calls 10177f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * Java MyMediaScanner handleStringTag. 10277f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * Once MediaScanner processFile returns, an entry is inserted in to the database. 1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@hide} 1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class MediaScanner 10720b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync{ 1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static { 1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project System.loadLibrary("media_jni"); 1104935d05eaa306cef88cf0ab13eca386f270409ecMarco Nelissen native_init(); 1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final static String TAG = "MediaScanner"; 1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 115d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood private static final String[] FILES_PRESCAN_PROJECTION = new String[] { 116c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood Files.FileColumns._ID, // 0 117c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood Files.FileColumns.DATA, // 1 118d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood Files.FileColumns.FORMAT, // 2 119d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood Files.FileColumns.DATE_MODIFIED, // 3 1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 12120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 1226458935331ccfacb4cccc50d6b893947febae687Mike Lockwood private static final String[] ID_PROJECTION = new String[] { 1236458935331ccfacb4cccc50d6b893947febae687Mike Lockwood Files.FileColumns._ID, 1246458935331ccfacb4cccc50d6b893947febae687Mike Lockwood }; 1256458935331ccfacb4cccc50d6b893947febae687Mike Lockwood 126d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood private static final int FILES_PRESCAN_ID_COLUMN_INDEX = 0; 127d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood private static final int FILES_PRESCAN_PATH_COLUMN_INDEX = 1; 128d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood private static final int FILES_PRESCAN_FORMAT_COLUMN_INDEX = 2; 129d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood private static final int FILES_PRESCAN_DATE_MODIFIED_COLUMN_INDEX = 3; 130d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood 1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String[] PLAYLIST_MEMBERS_PROJECTION = new String[] { 1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Audio.Playlists.Members.PLAYLIST_ID, // 0 1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int ID_PLAYLISTS_COLUMN_INDEX = 0; 1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int PATH_PLAYLISTS_COLUMN_INDEX = 1; 1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int DATE_MODIFIED_PLAYLISTS_COLUMN_INDEX = 2; 1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String[] GENRE_LOOKUP_PROJECTION = new String[] { 1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Audio.Genres._ID, // 0 1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Audio.Genres.NAME, // 1 1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String RINGTONES_DIR = "/ringtones/"; 1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String NOTIFICATIONS_DIR = "/notifications/"; 1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String ALARMS_DIR = "/alarms/"; 1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String MUSIC_DIR = "/music/"; 1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String PODCAST_DIR = "/podcasts/"; 14920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String[] ID3_GENRES = { 1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // ID3v1 Genres 1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Blues", 1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Classic Rock", 1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Country", 1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Dance", 1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Disco", 1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Funk", 1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Grunge", 1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Hip-Hop", 1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Jazz", 1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Metal", 1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "New Age", 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Oldies", 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Other", 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Pop", 1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "R&B", 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Rap", 1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Reggae", 1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Rock", 1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Techno", 1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Industrial", 1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Alternative", 1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Ska", 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Death Metal", 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Pranks", 1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Soundtrack", 1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Euro-Techno", 1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Ambient", 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Trip-Hop", 1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Vocal", 1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Jazz+Funk", 1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Fusion", 1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Trance", 1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Classical", 1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Instrumental", 1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Acid", 1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "House", 1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Game", 1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Sound Clip", 1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Gospel", 1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Noise", 1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "AlternRock", 1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Bass", 1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Soul", 1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Punk", 1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Space", 1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Meditative", 1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Instrumental Pop", 1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Instrumental Rock", 2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Ethnic", 2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Gothic", 2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Darkwave", 2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Techno-Industrial", 2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Electronic", 2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Pop-Folk", 2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Eurodance", 2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Dream", 2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Southern Rock", 2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Comedy", 2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Cult", 2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Gangsta", 2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Top 40", 2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Christian Rap", 2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Pop/Funk", 2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Jungle", 2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Native American", 2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Cabaret", 2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "New Wave", 2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Psychadelic", 2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Rave", 2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Showtunes", 2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Trailer", 2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Lo-Fi", 2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Tribal", 2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Acid Punk", 2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Acid Jazz", 2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Polka", 2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Retro", 2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Musical", 2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Rock & Roll", 2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Hard Rock", 2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // The following genres are Winamp extensions 2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Folk", 2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Folk-Rock", 2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "National Folk", 2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Swing", 2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Fast Fusion", 2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Bebob", 2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Latin", 2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Revival", 2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Celtic", 2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Bluegrass", 2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Avantgarde", 2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Gothic Rock", 2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Progressive Rock", 2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Psychedelic Rock", 2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Symphonic Rock", 2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Slow Rock", 2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Big Band", 2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Chorus", 2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Easy Listening", 2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Acoustic", 2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Humour", 2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Speech", 2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Chanson", 2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Opera", 2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Chamber Music", 2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Sonata", 2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Symphony", 2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Booty Bass", 2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Primus", 2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Porn Groove", 2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Satire", 2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Slow Jam", 2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Club", 2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Tango", 2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Samba", 2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Folklore", 2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Ballad", 2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Power Ballad", 2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Rhythmic Soul", 2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Freestyle", 2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Duet", 2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Punk Rock", 2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Drum Solo", 2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "A capella", 2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Euro-House", 2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Dance Hall" 2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mNativeContext; 2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Context mContext; 2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private IContentProvider mMediaProvider; 2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Uri mAudioUri; 2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Uri mVideoUri; 2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Uri mImagesUri; 2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Uri mThumbsUri; 2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Uri mGenresUri; 2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Uri mPlaylistsUri; 290c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood private Uri mFilesUri; 2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mProcessPlaylists, mProcessGenres; 292d815f79766984fce499e147ecbacc01914683f74Mike Lockwood private int mMtpObjectHandle; 2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 294250528e5b2362cb7b6749afb331acd8226f67744Mike Lockwood private final String mMediaStoragePath; 295250528e5b2362cb7b6749afb331acd8226f67744Mike Lockwood private final String mExternalStoragePath; 296250528e5b2362cb7b6749afb331acd8226f67744Mike Lockwood 2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // used when scanning the image database so we know whether we have to prune 2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // old thumbnail files 2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mOriginalCount; 3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** Whether the scanner has set a default sound for the ringer ringtone. */ 3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mDefaultRingtoneSet; 3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** Whether the scanner has set a default sound for the notification ringtone. */ 3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mDefaultNotificationSet; 3043156bb00dd3ab3d6ec732bb6a64a2e84d08c34f0Patrick Scott /** Whether the scanner has set a default sound for the alarm ringtone. */ 3053156bb00dd3ab3d6ec732bb6a64a2e84d08c34f0Patrick Scott private boolean mDefaultAlarmSet; 3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** The filename for the default sound for the ringer ringtone. */ 3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String mDefaultRingtoneFilename; 3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** The filename for the default sound for the notification ringtone. */ 3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String mDefaultNotificationFilename; 3103156bb00dd3ab3d6ec732bb6a64a2e84d08c34f0Patrick Scott /** The filename for the default sound for the alarm ringtone. */ 3113156bb00dd3ab3d6ec732bb6a64a2e84d08c34f0Patrick Scott private String mDefaultAlarmAlertFilename; 3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The prefix for system properties that define the default sound for 3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * ringtones. Concatenate the name of the setting from Settings 3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * to get the full system property. 3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String DEFAULT_RINGTONE_PROPERTY_PREFIX = "ro.config."; 31820b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // set to true if file path comparisons should be case insensitive. 3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // this should be set when scanning files on a case insensitive file system. 3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mCaseInsensitivePaths; 32220b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private BitmapFactory.Options mBitmapOptions = new BitmapFactory.Options(); 3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static class FileCacheEntry { 3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Uri mTableUri; 3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long mRowId; 3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String mPath; 3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long mLastModified; 330d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood int mFormat; 3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean mSeenInFileSystem; 3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean mLastModifiedChanged; 33320b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 334d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood FileCacheEntry(Uri tableUri, long rowId, String path, long lastModified, int format) { 3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mTableUri = tableUri; 3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mRowId = rowId; 3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPath = path; 3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLastModified = lastModified; 339d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood mFormat = format; 3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSeenInFileSystem = false; 3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLastModifiedChanged = false; 3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public String toString() { 346c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood return mPath + " mTableUri: " + mTableUri + " mRowId: " + mRowId; 3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 34920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 35020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync // hashes file path to FileCacheEntry. 3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // path should be lower case if mCaseInsensitivePaths is true 35220b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync private HashMap<String, FileCacheEntry> mFileCache; 3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private ArrayList<FileCacheEntry> mPlayLists; 3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private HashMap<String, Uri> mGenreCache; 3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3575d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang private DrmManagerClient mDrmManagerClient = null; 3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public MediaScanner(Context c) { 3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project native_setup(); 3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext = c; 3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mBitmapOptions.inSampleSize = 1; 3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mBitmapOptions.inJustDecodeBounds = true; 36420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setDefaultRingtoneFileNames(); 366250528e5b2362cb7b6749afb331acd8226f67744Mike Lockwood 367250528e5b2362cb7b6749afb331acd8226f67744Mike Lockwood String mediaStoragePath = SystemProperties.get("ro.media.storage"); 368250528e5b2362cb7b6749afb331acd8226f67744Mike Lockwood if (mediaStoragePath != null && mediaStoragePath.length() > 0) { 369250528e5b2362cb7b6749afb331acd8226f67744Mike Lockwood mMediaStoragePath = mediaStoragePath; 370250528e5b2362cb7b6749afb331acd8226f67744Mike Lockwood } else { 371250528e5b2362cb7b6749afb331acd8226f67744Mike Lockwood mMediaStoragePath = null; 372250528e5b2362cb7b6749afb331acd8226f67744Mike Lockwood } 373250528e5b2362cb7b6749afb331acd8226f67744Mike Lockwood mExternalStoragePath = Environment.getExternalStorageDirectory().getAbsolutePath(); 3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void setDefaultRingtoneFileNames() { 3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDefaultRingtoneFilename = SystemProperties.get(DEFAULT_RINGTONE_PROPERTY_PREFIX 3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + Settings.System.RINGTONE); 3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDefaultNotificationFilename = SystemProperties.get(DEFAULT_RINGTONE_PROPERTY_PREFIX 3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + Settings.System.NOTIFICATION_SOUND); 3813156bb00dd3ab3d6ec732bb6a64a2e84d08c34f0Patrick Scott mDefaultAlarmAlertFilename = SystemProperties.get(DEFAULT_RINGTONE_PROPERTY_PREFIX 3823156bb00dd3ab3d6ec732bb6a64a2e84d08c34f0Patrick Scott + Settings.System.ALARM_ALERT); 3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 38420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private MyMediaScannerClient mClient = new MyMediaScannerClient(); 38620b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 387e4eb4d9de37a8e9ed6f43a5f7deccf88f28bfc8bMarco Nelissen private boolean isDrmEnabled() { 3881f89c4f9f8df5d7125221250993ba1e853ed9fedGloria Wang String prop = SystemProperties.get("drm.service.enabled"); 389e4eb4d9de37a8e9ed6f43a5f7deccf88f28bfc8bMarco Nelissen return prop != null && prop.equals("true"); 390e4eb4d9de37a8e9ed6f43a5f7deccf88f28bfc8bMarco Nelissen } 391e4eb4d9de37a8e9ed6f43a5f7deccf88f28bfc8bMarco Nelissen 3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private class MyMediaScannerClient implements MediaScannerClient { 39320b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String mArtist; 3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String mAlbumArtist; // use this if mArtist is missing 3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String mAlbum; 3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String mTitle; 3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String mComposer; 3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String mGenre; 4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String mMimeType; 4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mFileType; 4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mTrack; 4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mYear; 4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mDuration; 4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String mPath; 4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private long mLastModified; 4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private long mFileSize; 408c9706f0262a2f399f95e0d78ba2b7616e08d0069Sahil Sachdeva private String mWriter; 40920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public FileCacheEntry beginFile(String path, String mimeType, long lastModified, long fileSize) { 41120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // special case certain file names 41320b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync // I use regionMatches() instead of substring() below 4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // to avoid memory allocation 4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int lastSlash = path.lastIndexOf('/'); 4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (lastSlash >= 0 && lastSlash + 2 < path.length()) { 4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // ignore those ._* files created by MacOS 4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (path.regionMatches(lastSlash + 1, "._", 0, 2)) { 4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 42120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // ignore album art files created by Windows Media Player: 4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Folder.jpg, AlbumArtSmall.jpg, AlbumArt_{...}_Large.jpg and AlbumArt_{...}_Small.jpg 4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (path.regionMatches(true, path.length() - 4, ".jpg", 0, 4)) { 4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (path.regionMatches(true, lastSlash + 1, "AlbumArt_{", 0, 10) || 4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project path.regionMatches(true, lastSlash + 1, "AlbumArt.", 0, 9)) { 4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int length = path.length() - lastSlash - 1; 4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if ((length == 17 && path.regionMatches(true, lastSlash + 1, "AlbumArtSmall", 0, 13)) || 4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (length == 10 && path.regionMatches(true, lastSlash + 1, "Folder", 0, 6))) { 4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 43620b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMimeType = null; 438c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood mFileType = 0; 439c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood mFileSize = fileSize; 440c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood 4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // try mimeType first, if it is specified 4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mimeType != null) { 4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mFileType = MediaFile.getFileTypeForMimeType(mimeType); 4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mFileType != 0) { 4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMimeType = mimeType; 4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // if mimeType was not specified, compute file type based on file extension. 4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mMimeType == null) { 4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MediaFile.MediaFileType mediaFileType = MediaFile.getFileType(path); 4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mediaFileType != null) { 4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mFileType = mediaFileType.fileType; 4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMimeType = mediaFileType.mimeType; 4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 45720b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 458e4eb4d9de37a8e9ed6f43a5f7deccf88f28bfc8bMarco Nelissen if (isDrmEnabled() && MediaFile.isDrmFileType(mFileType)) { 4595d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang mFileType = getFileTypeFromDrm(path); 4605d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang } 4615d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang 4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String key = path; 463250528e5b2362cb7b6749afb331acd8226f67744Mike Lockwood if (mMediaStoragePath != null && key.startsWith(mMediaStoragePath)) { 464250528e5b2362cb7b6749afb331acd8226f67744Mike Lockwood // MediaProvider uses external variant of path for _data, so we need to match 465250528e5b2362cb7b6749afb331acd8226f67744Mike Lockwood // against that path instead. 466250528e5b2362cb7b6749afb331acd8226f67744Mike Lockwood key = mExternalStoragePath + key.substring(mMediaStoragePath.length()); 467250528e5b2362cb7b6749afb331acd8226f67744Mike Lockwood } 4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mCaseInsensitivePaths) { 4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project key = path.toLowerCase(); 4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project FileCacheEntry entry = mFileCache.get(key); 4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (entry == null) { 473c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood Uri tableUri; 474c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood if (MediaFile.isVideoFileType(mFileType)) { 475c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood tableUri = mVideoUri; 476c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood } else if (MediaFile.isImageFileType(mFileType)) { 477c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood tableUri = mImagesUri; 478c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood } else if (MediaFile.isAudioFileType(mFileType)) { 479c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood tableUri = mAudioUri; 480c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood } else { 481c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood tableUri = mFilesUri; 482c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood } 483d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood entry = new FileCacheEntry(tableUri, 0, path, 0, 0); 4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mFileCache.put(key, entry); 4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project entry.mSeenInFileSystem = true; 48720b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // add some slack to avoid a rounding error 4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long delta = lastModified - entry.mLastModified; 4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (delta > 1 || delta < -1) { 4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project entry.mLastModified = lastModified; 4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project entry.mLastModifiedChanged = true; 4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 49420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mProcessPlaylists && MediaFile.isPlayListFileType(mFileType)) { 4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPlayLists.add(entry); 4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // we don't process playlists in the main scan, so return null 4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 50020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // clear all the metadata 5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mArtist = null; 5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAlbumArtist = null; 5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAlbum = null; 5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mTitle = null; 5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mComposer = null; 5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mGenre = null; 5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mTrack = 0; 5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mYear = 0; 5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDuration = 0; 5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPath = path; 5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLastModified = lastModified; 513c9706f0262a2f399f95e0d78ba2b7616e08d0069Sahil Sachdeva mWriter = null; 51420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return entry; 5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 51720b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void scanFile(String path, long lastModified, long fileSize) { 51900c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen // This is the callback funtion from native codes. 52000c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen // Log.v(TAG, "scanFile: "+path); 5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project doScanFile(path, null, lastModified, fileSize, false); 5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void scanFile(String path, String mimeType, long lastModified, long fileSize) { 5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project doScanFile(path, mimeType, lastModified, fileSize, false); 5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 528c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood public Uri doScanFile(String path, String mimeType, long lastModified, 529c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood long fileSize, boolean scanAlways) { 5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Uri result = null; 5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// long t1 = System.currentTimeMillis(); 5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project FileCacheEntry entry = beginFile(path, mimeType, lastModified, fileSize); 5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // rescan for metadata if file was modified since last scan 5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (entry != null && (entry.mLastModifiedChanged || scanAlways)) { 5369f0b1a48506af8e18162f62570561135b65a4ed1Marco Nelissen String lowpath = path.toLowerCase(); 5379f0b1a48506af8e18162f62570561135b65a4ed1Marco Nelissen boolean ringtones = (lowpath.indexOf(RINGTONES_DIR) > 0); 5389f0b1a48506af8e18162f62570561135b65a4ed1Marco Nelissen boolean notifications = (lowpath.indexOf(NOTIFICATIONS_DIR) > 0); 5399f0b1a48506af8e18162f62570561135b65a4ed1Marco Nelissen boolean alarms = (lowpath.indexOf(ALARMS_DIR) > 0); 5409f0b1a48506af8e18162f62570561135b65a4ed1Marco Nelissen boolean podcasts = (lowpath.indexOf(PODCAST_DIR) > 0); 5419f0b1a48506af8e18162f62570561135b65a4ed1Marco Nelissen boolean music = (lowpath.indexOf(MUSIC_DIR) > 0) || 5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (!ringtones && !notifications && !alarms && !podcasts); 5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 544c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood // we only extract metadata for audio and video files 545c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood if (MediaFile.isAudioFileType(mFileType) 546c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood || MediaFile.isVideoFileType(mFileType)) { 5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project processFile(path, mimeType, this); 5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 54920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project result = endFile(entry, ringtones, notifications, alarms, music, podcasts); 5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (RemoteException e) { 5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "RemoteException in MediaScanner.scanFile()", e); 5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// long t2 = System.currentTimeMillis(); 5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project// Log.v(TAG, "scanFile: " + path + " took " + (t2-t1)); 5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return result; 5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int parseSubstring(String s, int start, int defaultValue) { 5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int length = s.length(); 5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (start == length) return defaultValue; 5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char ch = s.charAt(start++); 5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // return defaultValue if we have no integer at all 5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (ch < '0' || ch > '9') return defaultValue; 56720b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int result = ch - '0'; 5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (start < length) { 5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ch = s.charAt(start++); 5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (ch < '0' || ch > '9') return result; 5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project result = result * 10 + (ch - '0'); 5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 57420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return result; 57620b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync } 57720b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void handleStringTag(String name, String value) { 5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (name.equalsIgnoreCase("title") || name.startsWith("title;")) { 58073bb511adee5444ecd041146fbbd3677fb635949Marco Nelissen // Don't trim() here, to preserve the special \001 character 58173bb511adee5444ecd041146fbbd3677fb635949Marco Nelissen // used to force sorting. The media provider will trim() before 58273bb511adee5444ecd041146fbbd3677fb635949Marco Nelissen // inserting the title in to the database. 58373bb511adee5444ecd041146fbbd3677fb635949Marco Nelissen mTitle = value; 5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (name.equalsIgnoreCase("artist") || name.startsWith("artist;")) { 5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mArtist = value.trim(); 586ed8188711a794867b47d21bbed3e26827f6c27e3Neel Parekh } else if (name.equalsIgnoreCase("albumartist") || name.startsWith("albumartist;") 587ed8188711a794867b47d21bbed3e26827f6c27e3Neel Parekh || name.equalsIgnoreCase("band") || name.startsWith("band;")) { 5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAlbumArtist = value.trim(); 5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (name.equalsIgnoreCase("album") || name.startsWith("album;")) { 5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAlbum = value.trim(); 5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (name.equalsIgnoreCase("composer") || name.startsWith("composer;")) { 5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mComposer = value.trim(); 5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (name.equalsIgnoreCase("genre") || name.startsWith("genre;")) { 5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // handle numeric genres, which PV sometimes encodes like "(20)" 5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (value.length() > 0) { 5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int genreCode = -1; 5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char ch = value.charAt(0); 5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (ch == '(') { 5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project genreCode = parseSubstring(value, 1, -1); 6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (ch >= '0' && ch <= '9') { 6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project genreCode = parseSubstring(value, 0, -1); 6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (genreCode >= 0 && genreCode < ID3_GENRES.length) { 6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project value = ID3_GENRES[genreCode]; 605bfcb22a207499c7ecd4aef9bea2ac778d8be8fc8Marco Nelissen } else if (genreCode == 255) { 606bfcb22a207499c7ecd4aef9bea2ac778d8be8fc8Marco Nelissen // 255 is defined to be unknown 607bfcb22a207499c7ecd4aef9bea2ac778d8be8fc8Marco Nelissen value = null; 6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mGenre = value; 6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (name.equalsIgnoreCase("year") || name.startsWith("year;")) { 6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mYear = parseSubstring(value, 0, 0); 6139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (name.equalsIgnoreCase("tracknumber") || name.startsWith("tracknumber;")) { 6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // track number might be of the form "2/12" 6159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // we just read the number before the slash 6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int num = parseSubstring(value, 0, 0); 61720b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync mTrack = (mTrack / 1000) * 1000 + num; 6189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (name.equalsIgnoreCase("discnumber") || 6199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project name.equals("set") || name.startsWith("set;")) { 6209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // set number might be of the form "1/3" 6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // we just read the number before the slash 6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int num = parseSubstring(value, 0, 0); 6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mTrack = (num * 1000) + (mTrack % 1000); 6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (name.equalsIgnoreCase("duration")) { 6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDuration = parseSubstring(value, 0, 0); 626c9706f0262a2f399f95e0d78ba2b7616e08d0069Sahil Sachdeva } else if (name.equalsIgnoreCase("writer") || name.startsWith("writer;")) { 627c9706f0262a2f399f95e0d78ba2b7616e08d0069Sahil Sachdeva mWriter = value.trim(); 6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 63020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 6319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setMimeType(String mimeType) { 6321851db6804cbdf8d2c8ede0725e73be6fda0f3c0Marco Nelissen if ("audio/mp4".equals(mMimeType) && 6331851db6804cbdf8d2c8ede0725e73be6fda0f3c0Marco Nelissen mimeType.startsWith("video")) { 6341851db6804cbdf8d2c8ede0725e73be6fda0f3c0Marco Nelissen // for feature parity with Donut, we force m4a files to keep the 6351851db6804cbdf8d2c8ede0725e73be6fda0f3c0Marco Nelissen // audio/mp4 mimetype, even if they are really "enhanced podcasts" 6361851db6804cbdf8d2c8ede0725e73be6fda0f3c0Marco Nelissen // with a video track 6371851db6804cbdf8d2c8ede0725e73be6fda0f3c0Marco Nelissen return; 6381851db6804cbdf8d2c8ede0725e73be6fda0f3c0Marco Nelissen } 6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMimeType = mimeType; 6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mFileType = MediaFile.getFileTypeForMimeType(mimeType); 6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 64220b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Formats the data into a values array suitable for use with the Media 6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Content Provider. 64620b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync * 6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return a map of values 6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private ContentValues toValues() { 6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ContentValues map = new ContentValues(); 6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project map.put(MediaStore.MediaColumns.DATA, mPath); 6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project map.put(MediaStore.MediaColumns.TITLE, mTitle); 6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project map.put(MediaStore.MediaColumns.DATE_MODIFIED, mLastModified); 6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project map.put(MediaStore.MediaColumns.SIZE, mFileSize); 6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project map.put(MediaStore.MediaColumns.MIME_TYPE, mMimeType); 65720b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (MediaFile.isVideoFileType(mFileType)) { 6599a488b44cb479bc42375d2cfcdd4aa6161dc17cfMarco Nelissen map.put(Video.Media.ARTIST, (mArtist != null && mArtist.length() > 0 ? mArtist : MediaStore.UNKNOWN_STRING)); 6609a488b44cb479bc42375d2cfcdd4aa6161dc17cfMarco Nelissen map.put(Video.Media.ALBUM, (mAlbum != null && mAlbum.length() > 0 ? mAlbum : MediaStore.UNKNOWN_STRING)); 6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project map.put(Video.Media.DURATION, mDuration); 6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // FIXME - add RESOLUTION 6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (MediaFile.isImageFileType(mFileType)) { 6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // FIXME - add DESCRIPTION 6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (MediaFile.isAudioFileType(mFileType)) { 6660096b8d7d119281466763160d5c88c5f9832d005Marco Nelissen map.put(Audio.Media.ARTIST, (mArtist != null && mArtist.length() > 0) ? 6670096b8d7d119281466763160d5c88c5f9832d005Marco Nelissen mArtist : MediaStore.UNKNOWN_STRING); 668920d649949f6636a9e4220904c9a3c5cd860fd53Marco Nelissen map.put(Audio.Media.ALBUM_ARTIST, (mAlbumArtist != null && 669920d649949f6636a9e4220904c9a3c5cd860fd53Marco Nelissen mAlbumArtist.length() > 0) ? mAlbumArtist : null); 6700096b8d7d119281466763160d5c88c5f9832d005Marco Nelissen map.put(Audio.Media.ALBUM, (mAlbum != null && mAlbum.length() > 0) ? 6710096b8d7d119281466763160d5c88c5f9832d005Marco Nelissen mAlbum : MediaStore.UNKNOWN_STRING); 6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project map.put(Audio.Media.COMPOSER, mComposer); 6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mYear != 0) { 6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project map.put(Audio.Media.YEAR, mYear); 6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project map.put(Audio.Media.TRACK, mTrack); 6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project map.put(Audio.Media.DURATION, mDuration); 6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return map; 6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 68120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 6829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Uri endFile(FileCacheEntry entry, boolean ringtones, boolean notifications, 68320b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync boolean alarms, boolean music, boolean podcasts) 6849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throws RemoteException { 6859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // update database 68620b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // use album artist if artist is missing 6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mArtist == null || mArtist.length() == 0) { 6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mArtist = mAlbumArtist; 6909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ContentValues values = toValues(); 6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String title = values.getAsString(MediaStore.MediaColumns.TITLE); 694bdc0e82f9c075edb67da4a2583e557824c280415Mike Lockwood if (title == null || TextUtils.isEmpty(title.trim())) { 695c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood title = MediaFile.getFileTitle(values.getAsString(MediaStore.MediaColumns.DATA)); 6969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project values.put(MediaStore.MediaColumns.TITLE, title); 6979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 698c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen String album = values.getAsString(Audio.Media.ALBUM); 6999a488b44cb479bc42375d2cfcdd4aa6161dc17cfMarco Nelissen if (MediaStore.UNKNOWN_STRING.equals(album)) { 700c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen album = values.getAsString(MediaStore.MediaColumns.DATA); 701c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen // extract last path segment before file name 702c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen int lastSlash = album.lastIndexOf('/'); 703c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen if (lastSlash >= 0) { 704c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen int previousSlash = 0; 705c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen while (true) { 706c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen int idx = album.indexOf('/', previousSlash + 1); 707c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen if (idx < 0 || idx >= lastSlash) { 708c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen break; 709c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen } 710c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen previousSlash = idx; 711c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen } 712c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen if (previousSlash != 0) { 713c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen album = album.substring(previousSlash + 1, lastSlash); 714c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen values.put(Audio.Media.ALBUM, album); 715c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen } 716c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen } 717c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen } 718c066557378c2305625a7bad3d25f084ad647ef27Marco Nelissen long rowId = entry.mRowId; 719c2206a0710a3ca2c29854c1a0638c5ba55629ba2Mike Lockwood if (MediaFile.isAudioFileType(mFileType) && (rowId == 0 || mMtpObjectHandle != 0)) { 720c066557378c2305625a7bad3d25f084ad647ef27Marco Nelissen // Only set these for new entries. For existing entries, they 721c066557378c2305625a7bad3d25f084ad647ef27Marco Nelissen // may have been modified later, and we want to keep the current 722c066557378c2305625a7bad3d25f084ad647ef27Marco Nelissen // values so that custom ringtones still show up in the ringtone 723c066557378c2305625a7bad3d25f084ad647ef27Marco Nelissen // picker. 7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project values.put(Audio.Media.IS_RINGTONE, ringtones); 7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project values.put(Audio.Media.IS_NOTIFICATION, notifications); 7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project values.put(Audio.Media.IS_ALARM, alarms); 7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project values.put(Audio.Media.IS_MUSIC, music); 7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project values.put(Audio.Media.IS_PODCAST, podcasts); 72920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync } else if (mFileType == MediaFile.FILE_TYPE_JPEG) { 730700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang ExifInterface exif = null; 731700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang try { 732700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang exif = new ExifInterface(entry.mPath); 733700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang } catch (IOException ex) { 734700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang // exif is null 735700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang } 736700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang if (exif != null) { 737872a30ec723ebdd97de764406544516545d7c9d4Chih-Chung Chang float[] latlng = new float[2]; 738872a30ec723ebdd97de764406544516545d7c9d4Chih-Chung Chang if (exif.getLatLong(latlng)) { 73920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync values.put(Images.Media.LATITUDE, latlng[0]); 74020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync values.put(Images.Media.LONGITUDE, latlng[1]); 74120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync } 742099397cbd07c8c991f3126d0d0ac64bb6b3c0b47Chih-Chung Chang 7433a8cab88e7747dc280ce85895af014f98e80a6ccRay Chen long time = exif.getGpsDateTime(); 744099397cbd07c8c991f3126d0d0ac64bb6b3c0b47Chih-Chung Chang if (time != -1) { 745052d9c8b414dc9eb1c70d849660592d9bc3b2644Ray Chen values.put(Images.Media.DATE_TAKEN, time); 746099397cbd07c8c991f3126d0d0ac64bb6b3c0b47Chih-Chung Chang } 747b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang 748b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang int orientation = exif.getAttributeInt( 749b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang ExifInterface.TAG_ORIENTATION, -1); 750b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang if (orientation != -1) { 751b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang // We only recognize a subset of orientation tag values. 752b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang int degree; 753b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang switch(orientation) { 754b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang case ExifInterface.ORIENTATION_ROTATE_90: 755b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang degree = 90; 756b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang break; 757b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang case ExifInterface.ORIENTATION_ROTATE_180: 758b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang degree = 180; 759b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang break; 760b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang case ExifInterface.ORIENTATION_ROTATE_270: 761b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang degree = 270; 762b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang break; 763b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang default: 764b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang degree = 0; 765b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang break; 766b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang } 767b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang values.put(Images.Media.ORIENTATION, degree); 768b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang } 76920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync } 7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 77120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 772c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood Uri tableUri = entry.mTableUri; 7739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Uri result = null; 7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (rowId == 0) { 775c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood if (mMtpObjectHandle != 0) { 776c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood values.put(MediaStore.MediaColumns.MEDIA_SCANNER_NEW_OBJECT_ID, mMtpObjectHandle); 777c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood } 778c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood if (tableUri == mFilesUri) { 779c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood values.put(Files.FileColumns.FORMAT, MediaFile.getFormatCode(entry.mPath, mMimeType)); 780c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood } 7819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // new file, insert it 7829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project result = mMediaProvider.insert(tableUri, values); 7839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (result != null) { 7849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project rowId = ContentUris.parseId(result); 7859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project entry.mRowId = rowId; 7869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 7889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // updated file 7899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project result = ContentUris.withAppendedId(tableUri, rowId); 7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaProvider.update(result, values, null, null); 7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mProcessGenres && mGenre != null) { 7939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String genre = mGenre; 7949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Uri uri = mGenreCache.get(genre); 7959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (uri == null) { 7969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Cursor cursor = null; 7979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 7989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // see if the genre already exists 7999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project cursor = mMediaProvider.query( 8009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mGenresUri, 8019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project GENRE_LOOKUP_PROJECTION, MediaStore.Audio.Genres.NAME + "=?", 8029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project new String[] { genre }, null); 8039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (cursor == null || cursor.getCount() == 0) { 8049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // genre does not exist, so create the genre in the genre table 8059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project values.clear(); 8069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project values.put(MediaStore.Audio.Genres.NAME, genre); 8079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project uri = mMediaProvider.insert(mGenresUri, values); 8089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 8099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // genre already exists, so compute its Uri 8109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project cursor.moveToNext(); 8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project uri = ContentUris.withAppendedId(mGenresUri, cursor.getLong(0)); 8129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (uri != null) { 8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project uri = Uri.withAppendedPath(uri, Genres.Members.CONTENT_DIRECTORY); 8159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mGenreCache.put(genre, uri); 8169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 8189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // release the cursor if it exists 8199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (cursor != null) { 8209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project cursor.close(); 8219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 82420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 8259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (uri != null) { 82620b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync // add entry to audio_genre_map 8279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project values.clear(); 8289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project values.put(MediaStore.Audio.Genres.Members.AUDIO_ID, Long.valueOf(rowId)); 8299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaProvider.insert(uri, values); 8309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 83220b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 8339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (notifications && !mDefaultNotificationSet) { 8349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (TextUtils.isEmpty(mDefaultNotificationFilename) || 8359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project doesPathHaveFilename(entry.mPath, mDefaultNotificationFilename)) { 8369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setSettingIfNotSet(Settings.System.NOTIFICATION_SOUND, tableUri, rowId); 8379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDefaultNotificationSet = true; 8389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (ringtones && !mDefaultRingtoneSet) { 8409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (TextUtils.isEmpty(mDefaultRingtoneFilename) || 8419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project doesPathHaveFilename(entry.mPath, mDefaultRingtoneFilename)) { 8429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setSettingIfNotSet(Settings.System.RINGTONE, tableUri, rowId); 8439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDefaultRingtoneSet = true; 8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8453156bb00dd3ab3d6ec732bb6a64a2e84d08c34f0Patrick Scott } else if (alarms && !mDefaultAlarmSet) { 8463156bb00dd3ab3d6ec732bb6a64a2e84d08c34f0Patrick Scott if (TextUtils.isEmpty(mDefaultAlarmAlertFilename) || 8473156bb00dd3ab3d6ec732bb6a64a2e84d08c34f0Patrick Scott doesPathHaveFilename(entry.mPath, mDefaultAlarmAlertFilename)) { 8483156bb00dd3ab3d6ec732bb6a64a2e84d08c34f0Patrick Scott setSettingIfNotSet(Settings.System.ALARM_ALERT, tableUri, rowId); 8493156bb00dd3ab3d6ec732bb6a64a2e84d08c34f0Patrick Scott mDefaultAlarmSet = true; 8503156bb00dd3ab3d6ec732bb6a64a2e84d08c34f0Patrick Scott } 8519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 85220b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 8539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return result; 8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 85520b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean doesPathHaveFilename(String path, String filename) { 8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int pathFilenameStart = path.lastIndexOf(File.separatorChar) + 1; 8589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int filenameLength = filename.length(); 8599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return path.regionMatches(pathFilenameStart, filename, 0, filenameLength) && 8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project pathFilenameStart + filenameLength == path.length(); 8619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 86220b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 8639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void setSettingIfNotSet(String settingName, Uri uri, long rowId) { 86420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 8659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String existingSettingValue = Settings.System.getString(mContext.getContentResolver(), 8669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project settingName); 86720b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 8689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (TextUtils.isEmpty(existingSettingValue)) { 8699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Set the setting to the given URI 8709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Settings.System.putString(mContext.getContentResolver(), settingName, 8719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ContentUris.withAppendedId(uri, rowId).toString()); 8729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 87420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 8758b0466170082fdf12f78d7b70358002520e99e9bMarco Nelissen public void addNoMediaFolder(String path) { 8768b0466170082fdf12f78d7b70358002520e99e9bMarco Nelissen ContentValues values = new ContentValues(); 8778b0466170082fdf12f78d7b70358002520e99e9bMarco Nelissen values.put(MediaStore.Images.ImageColumns.DATA, ""); 8788b0466170082fdf12f78d7b70358002520e99e9bMarco Nelissen String [] pathSpec = new String[] {path + '%'}; 8798b0466170082fdf12f78d7b70358002520e99e9bMarco Nelissen try { 88033f49c8377ea9ffebaca9c398fb3c0f9585f9fe8Marco Nelissen // These tables have DELETE_FILE triggers that delete the file from the 88133f49c8377ea9ffebaca9c398fb3c0f9585f9fe8Marco Nelissen // sd card when deleting the database entry. We don't want to do this in 88233f49c8377ea9ffebaca9c398fb3c0f9585f9fe8Marco Nelissen // this case, since it would cause those files to be removed if a .nomedia 88333f49c8377ea9ffebaca9c398fb3c0f9585f9fe8Marco Nelissen // file was added after the fact, when in that case we only want the database 88433f49c8377ea9ffebaca9c398fb3c0f9585f9fe8Marco Nelissen // entries to be removed. 8858b0466170082fdf12f78d7b70358002520e99e9bMarco Nelissen mMediaProvider.update(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values, 8868b0466170082fdf12f78d7b70358002520e99e9bMarco Nelissen MediaStore.Images.ImageColumns.DATA + " LIKE ?", pathSpec); 8878b0466170082fdf12f78d7b70358002520e99e9bMarco Nelissen mMediaProvider.update(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, values, 8888b0466170082fdf12f78d7b70358002520e99e9bMarco Nelissen MediaStore.Images.ImageColumns.DATA + " LIKE ?", pathSpec); 8898b0466170082fdf12f78d7b70358002520e99e9bMarco Nelissen } catch (RemoteException e) { 8908b0466170082fdf12f78d7b70358002520e99e9bMarco Nelissen throw new RuntimeException(); 8918b0466170082fdf12f78d7b70358002520e99e9bMarco Nelissen } 8928b0466170082fdf12f78d7b70358002520e99e9bMarco Nelissen } 8938b0466170082fdf12f78d7b70358002520e99e9bMarco Nelissen 8945d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang private int getFileTypeFromDrm(String path) { 895e4eb4d9de37a8e9ed6f43a5f7deccf88f28bfc8bMarco Nelissen if (!isDrmEnabled()) { 8965d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang return 0; 8975d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang } 8985d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang 8995d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang int resultFileType = 0; 9005d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang 9015d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang if (mDrmManagerClient == null) { 9025d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang mDrmManagerClient = new DrmManagerClient(mContext); 9035d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang } 9045d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang 9055d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang if (mDrmManagerClient.canHandle(path, null)) { 9065d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang String drmMimetype = mDrmManagerClient.getOriginalMimeType(path); 9075d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang if (drmMimetype != null) { 9085d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang mMimeType = drmMimetype; 9095d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang resultFileType = MediaFile.getFileTypeForMimeType(drmMimetype); 9105d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang } 9115d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang } 9125d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang return resultFileType; 9135d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang } 9145d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang 9159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; // end of anonymous MediaScannerClient instance 91620b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 917c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood private void prescan(String filePath, boolean prescanFiles) throws RemoteException { 9189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Cursor c = null; 9199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String where = null; 9209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String[] selectionArgs = null; 92120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 9229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mFileCache == null) { 9239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mFileCache = new HashMap<String, FileCacheEntry>(); 9249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 9259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mFileCache.clear(); 9269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mPlayLists == null) { 9289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPlayLists = new ArrayList<FileCacheEntry>(); 9299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 9309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPlayLists.clear(); 9319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 93220b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 933c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood if (filePath != null) { 934250528e5b2362cb7b6749afb331acd8226f67744Mike Lockwood if (mMediaStoragePath != null && filePath.startsWith(mMediaStoragePath)) { 935250528e5b2362cb7b6749afb331acd8226f67744Mike Lockwood // MediaProvider uses external variant of path for _data, so we need to query 936250528e5b2362cb7b6749afb331acd8226f67744Mike Lockwood // using that path instead. 937250528e5b2362cb7b6749afb331acd8226f67744Mike Lockwood filePath = mExternalStoragePath + filePath.substring(mMediaStoragePath.length()); 938250528e5b2362cb7b6749afb331acd8226f67744Mike Lockwood } 939250528e5b2362cb7b6749afb331acd8226f67744Mike Lockwood 940c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood // query for only one file 941c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood where = Files.FileColumns.DATA + "=?"; 942c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood selectionArgs = new String[] { filePath }; 943c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood } 944c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood 9459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Build the list of files from the content provider 9469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 947c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood if (prescanFiles) { 948c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood // First read existing files from the files table 94920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 950d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood c = mMediaProvider.query(mFilesUri, FILES_PRESCAN_PROJECTION, 951d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood where, selectionArgs, null); 952c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood 953c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood if (c != null) { 9549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (c.moveToNext()) { 955d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood long rowId = c.getLong(FILES_PRESCAN_ID_COLUMN_INDEX); 956d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood String path = c.getString(FILES_PRESCAN_PATH_COLUMN_INDEX); 957d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood int format = c.getInt(FILES_PRESCAN_FORMAT_COLUMN_INDEX); 958d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood long lastModified = c.getLong(FILES_PRESCAN_DATE_MODIFIED_COLUMN_INDEX); 95920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 96035b002a9c873fb40116179c8626b9841b0abae74Marco Nelissen // Only consider entries with absolute path names. 96135b002a9c873fb40116179c8626b9841b0abae74Marco Nelissen // This allows storing URIs in the database without the 96235b002a9c873fb40116179c8626b9841b0abae74Marco Nelissen // media scanner removing them. 96335b002a9c873fb40116179c8626b9841b0abae74Marco Nelissen if (path.startsWith("/")) { 96435b002a9c873fb40116179c8626b9841b0abae74Marco Nelissen String key = path; 96535b002a9c873fb40116179c8626b9841b0abae74Marco Nelissen if (mCaseInsensitivePaths) { 96635b002a9c873fb40116179c8626b9841b0abae74Marco Nelissen key = path.toLowerCase(); 96735b002a9c873fb40116179c8626b9841b0abae74Marco Nelissen } 968c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood 969c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood FileCacheEntry entry = new FileCacheEntry(mFilesUri, rowId, path, 970d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood lastModified, format); 971c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood mFileCache.put(key, entry); 9729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project c.close(); 9759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project c = null; 9769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project finally { 9809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (c != null) { 9819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project c.close(); 9829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9846458935331ccfacb4cccc50d6b893947febae687Mike Lockwood 9856458935331ccfacb4cccc50d6b893947febae687Mike Lockwood // compute original size of images 9866458935331ccfacb4cccc50d6b893947febae687Mike Lockwood mOriginalCount = 0; 9876458935331ccfacb4cccc50d6b893947febae687Mike Lockwood c = mMediaProvider.query(mImagesUri, ID_PROJECTION, null, null, null); 9886458935331ccfacb4cccc50d6b893947febae687Mike Lockwood if (c != null) { 9896458935331ccfacb4cccc50d6b893947febae687Mike Lockwood mOriginalCount = c.getCount(); 9906458935331ccfacb4cccc50d6b893947febae687Mike Lockwood c.close(); 9916458935331ccfacb4cccc50d6b893947febae687Mike Lockwood } 9929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 99320b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 9949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean inScanDirectory(String path, String[] directories) { 9959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < directories.length; i++) { 9969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (path.startsWith(directories[i])) { 9979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 9989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 10019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 100220b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 10039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void pruneDeadThumbnailFiles() { 10049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project HashSet<String> existingFiles = new HashSet<String>(); 10059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String directory = "/sdcard/DCIM/.thumbnails"; 10069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String [] files = (new File(directory)).list(); 10079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (files == null) 10089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project files = new String[0]; 100920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 10109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < files.length; i++) { 10119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String fullPathString = directory + "/" + files[i]; 10129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project existingFiles.add(fullPathString); 10139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 101420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 10159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 10169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Cursor c = mMediaProvider.query( 101720b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync mThumbsUri, 101820b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync new String [] { "_data" }, 101920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync null, 102020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync null, 10219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project null); 10229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.v(TAG, "pruneDeadThumbnailFiles... " + c); 10239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (c != null && c.moveToFirst()) { 10249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project do { 10259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String fullPathString = c.getString(0); 10269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project existingFiles.remove(fullPathString); 10279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } while (c.moveToNext()); 10289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 102920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 10309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (String fileToDelete : existingFiles) { 10319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (Config.LOGV) 10329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.v(TAG, "fileToDelete is " + fileToDelete); 10339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 10349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (new File(fileToDelete)).delete(); 10359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (SecurityException ex) { 10369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 103820b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 10399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.v(TAG, "/pruneDeadThumbnailFiles... " + c); 10409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (c != null) { 10419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project c.close(); 10429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (RemoteException e) { 10449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // We will soon be killed... 10459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void postscan(String[] directories) throws RemoteException { 10499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Iterator<FileCacheEntry> iterator = mFileCache.values().iterator(); 10509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (iterator.hasNext()) { 10529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project FileCacheEntry entry = iterator.next(); 10539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String path = entry.mPath; 105420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 10559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // remove database entries for files that no longer exist. 10569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean fileMissing = false; 105720b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 1058d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood if (!entry.mSeenInFileSystem && !MtpConstants.isAbstractObject(entry.mFormat)) { 1059d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood if (entry.mFormat != MtpConstants.FORMAT_ASSOCIATION && 1060d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood inScanDirectory(path, directories)) { 10619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // we didn't see this file in the scan directory. 10629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fileMissing = true; 10639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 1064d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood // the file actually a directory or other abstract object 1065d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood // or is outside of our scan directory, 10669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // so we need to check for file existence here. 10679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project File testFile = new File(path); 10689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!testFile.exists()) { 10699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fileMissing = true; 10709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 107320b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 10749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (fileMissing) { 10759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // do not delete missing playlists, since they may have been modified by the user. 10769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // the user can delete them in the media player instead. 10779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // instead, clear the path and lastModified fields in the row 10789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MediaFile.MediaFileType mediaFileType = MediaFile.getFileType(path); 10799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int fileType = (mediaFileType == null ? 0 : mediaFileType.fileType); 10809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (MediaFile.isPlayListFileType(fileType)) { 10829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ContentValues values = new ContentValues(); 10839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project values.put(MediaStore.Audio.Playlists.DATA, ""); 10849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project values.put(MediaStore.Audio.Playlists.DATE_MODIFIED, 0); 1085d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood mMediaProvider.update(ContentUris.withAppendedId(mPlaylistsUri, entry.mRowId), 1086d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood values, null, null); 10879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 1088d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood mMediaProvider.delete(ContentUris.withAppendedId(mFilesUri, entry.mRowId), 1089d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood null, null); 10909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project iterator.remove(); 10919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 109420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 10959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // handle playlists last, after we know what media files are on the storage. 10969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mProcessPlaylists) { 10979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project processPlayLists(); 10989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 109920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 11009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mOriginalCount == 0 && mImagesUri.equals(Images.Media.getContentUri("external"))) 11019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project pruneDeadThumbnailFiles(); 110220b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 11039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // allow GC to clean up 11049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mGenreCache = null; 11059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPlayLists = null; 11069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mFileCache = null; 11079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaProvider = null; 11089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 110920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 11109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void initialize(String volumeName) { 11119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaProvider = mContext.getContentResolver().acquireProvider("media"); 111220b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 11139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAudioUri = Audio.Media.getContentUri(volumeName); 11149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mVideoUri = Video.Media.getContentUri(volumeName); 11159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mImagesUri = Images.Media.getContentUri(volumeName); 11169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mThumbsUri = Images.Thumbnails.getContentUri(volumeName); 1117c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood mFilesUri = Files.getContentUri(volumeName); 11189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!volumeName.equals("internal")) { 11209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // we only support playlists on external media 11219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mProcessPlaylists = true; 11229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mProcessGenres = true; 11239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mGenreCache = new HashMap<String, Uri>(); 11249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mGenresUri = Genres.getContentUri(volumeName); 11259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPlaylistsUri = Playlists.getContentUri(volumeName); 1126f73738b78a8396552274cf33b0021f414fb7201dMike Lockwood 1127f73738b78a8396552274cf33b0021f414fb7201dMike Lockwood mCaseInsensitivePaths = !mContext.getResources().getBoolean( 1128f73738b78a8396552274cf33b0021f414fb7201dMike Lockwood com.android.internal.R.bool.config_caseSensitiveExternalStorage); 1129f73738b78a8396552274cf33b0021f414fb7201dMike Lockwood if (!Process.supportsProcesses()) { 1130f73738b78a8396552274cf33b0021f414fb7201dMike Lockwood // Simulator uses host file system, so it should be case sensitive. 1131f73738b78a8396552274cf33b0021f414fb7201dMike Lockwood mCaseInsensitivePaths = false; 11329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 113320b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync } 11349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void scanDirectories(String[] directories, String volumeName) { 11379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 11389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long start = System.currentTimeMillis(); 113920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync initialize(volumeName); 1140c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood prescan(null, true); 11419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long prescan = System.currentTimeMillis(); 114220b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 11439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < directories.length; i++) { 1144c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood processDirectory(directories[i], mClient); 11459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long scan = System.currentTimeMillis(); 11479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project postscan(directories); 11489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long end = System.currentTimeMillis(); 114920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 11509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (Config.LOGD) { 11519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.d(TAG, " prescan time: " + (prescan - start) + "ms\n"); 11529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.d(TAG, " scan time: " + (scan - prescan) + "ms\n"); 11539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.d(TAG, "postscan time: " + (end - scan) + "ms\n"); 11549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.d(TAG, " total time: " + (end - start) + "ms\n"); 11559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (SQLException e) { 11579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // this might happen if the SD card is removed while the media scanner is running 11589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "SQLException in MediaScanner.scan()", e); 11599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (UnsupportedOperationException e) { 11609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // this might happen if the SD card is removed while the media scanner is running 11619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "UnsupportedOperationException in MediaScanner.scan()", e); 11629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (RemoteException e) { 11639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "RemoteException in MediaScanner.scan()", e); 11649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // this function is used to scan a single file 11689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Uri scanSingleFile(String path, String volumeName, String mimeType) { 11699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 117020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync initialize(volumeName); 1171c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood prescan(path, true); 117220b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 11739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project File file = new File(path); 1174ec74abb71f79cdc573c536115acc7ff26a02680aMikael 1175ec74abb71f79cdc573c536115acc7ff26a02680aMikael // lastModified is in milliseconds on Files. 1176ec74abb71f79cdc573c536115acc7ff26a02680aMikael long lastModifiedSeconds = file.lastModified() / 1000; 1177ec74abb71f79cdc573c536115acc7ff26a02680aMikael 11789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // always scan the file, so we can return the content://media Uri for existing files 1179ec74abb71f79cdc573c536115acc7ff26a02680aMikael return mClient.doScanFile(path, mimeType, lastModifiedSeconds, file.length(), true); 11809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (RemoteException e) { 11819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "RemoteException in MediaScanner.scanFile()", e); 11829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 11839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1186c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood public void scanMtpFile(String path, String volumeName, int objectHandle, int format) { 1187c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood MediaFile.MediaFileType mediaFileType = MediaFile.getFileType(path); 1188c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood int fileType = (mediaFileType == null ? 0 : mediaFileType.fileType); 1189c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood 1190c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood if (!MediaFile.isAudioFileType(fileType) && !MediaFile.isVideoFileType(fileType) && 1191c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood !MediaFile.isImageFileType(fileType) && !MediaFile.isPlayListFileType(fileType)) { 1192c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood // nothing to do 1193c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood return; 1194c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood } 1195c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood 1196d815f79766984fce499e147ecbacc01914683f74Mike Lockwood mMtpObjectHandle = objectHandle; 1197c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood try { 1198c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood initialize(volumeName); 1199c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood // MTP will create a file entry for us so we don't want to do it in prescan 1200c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood prescan(path, false); 1201c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood 1202c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood File file = new File(path); 1203c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood 1204c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood // lastModified is in milliseconds on Files. 1205c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood long lastModifiedSeconds = file.lastModified() / 1000; 1206c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood 1207c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood // always scan the file, so we can return the content://media Uri for existing files 1208c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood mClient.doScanFile(path, mediaFileType.mimeType, lastModifiedSeconds, file.length(), true); 1209c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood } catch (RemoteException e) { 1210c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood Log.e(TAG, "RemoteException in MediaScanner.scanFile()", e); 1211c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood } finally { 1212c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood mMtpObjectHandle = 0; 1213c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood } 1214d815f79766984fce499e147ecbacc01914683f74Mike Lockwood } 1215d815f79766984fce499e147ecbacc01914683f74Mike Lockwood 12169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // returns the number of matching file/directory names, starting from the right 12179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int matchPaths(String path1, String path2) { 12189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int result = 0; 12199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int end1 = path1.length(); 12209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int end2 = path2.length(); 122120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 12229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (end1 > 0 && end2 > 0) { 12239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int slash1 = path1.lastIndexOf('/', end1 - 1); 12249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int slash2 = path2.lastIndexOf('/', end2 - 1); 12259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int backSlash1 = path1.lastIndexOf('\\', end1 - 1); 12269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int backSlash2 = path2.lastIndexOf('\\', end2 - 1); 12279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int start1 = (slash1 > backSlash1 ? slash1 : backSlash1); 12289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int start2 = (slash2 > backSlash2 ? slash2 : backSlash2); 12299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (start1 < 0) start1 = 0; else start1++; 12309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (start2 < 0) start2 = 0; else start2++; 12319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int length = end1 - start1; 12329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (end2 - start2 != length) break; 12339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (path1.regionMatches(true, start1, path2, start2, length)) { 12349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project result++; 12359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project end1 = start1 - 1; 12369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project end2 = start2 - 1; 12379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else break; 12389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 123920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 12409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return result; 12419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 124320b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync private boolean addPlayListEntry(String entry, String playListDirectory, 12449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Uri uri, ContentValues values, int index) { 124520b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 12469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // watch for trailing whitespace 12479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int entryLength = entry.length(); 12489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (entryLength > 0 && Character.isWhitespace(entry.charAt(entryLength - 1))) entryLength--; 12499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // path should be longer than 3 characters. 12509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // avoid index out of bounds errors below by returning here. 12519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (entryLength < 3) return false; 12529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (entryLength < entry.length()) entry = entry.substring(0, entryLength); 12539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // does entry appear to be an absolute path? 12559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // look for Unix or DOS absolute paths 12569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project char ch1 = entry.charAt(0); 12579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean fullPath = (ch1 == '/' || 12589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (Character.isLetter(ch1) && entry.charAt(1) == ':' && entry.charAt(2) == '\\')); 12599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // if we have a relative path, combine entry with playListDirectory 12609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!fullPath) 12619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project entry = playListDirectory + entry; 126220b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 12639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project //FIXME - should we look for "../" within the path? 126420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 12659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // best matching MediaFile for the play list entry 12669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project FileCacheEntry bestMatch = null; 126720b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 12689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // number of rightmost file/directory names for bestMatch 126920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync int bestMatchLength = 0; 127020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 12719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Iterator<FileCacheEntry> iterator = mFileCache.values().iterator(); 12729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (iterator.hasNext()) { 12739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project FileCacheEntry cacheEntry = iterator.next(); 12749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String path = cacheEntry.mPath; 127520b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 12769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (path.equalsIgnoreCase(entry)) { 12779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bestMatch = cacheEntry; 12789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; // don't bother continuing search 12799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 128020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 12819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int matchLength = matchPaths(path, entry); 12829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (matchLength > bestMatchLength) { 12839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bestMatch = cacheEntry; 12849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bestMatchLength = matchLength; 12859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 128720b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 1288d4f3586c93cd9c29056e95cd79f3cb19ac456f3bMarco Nelissen // if the match is not for an audio file, bail out 1289d4f3586c93cd9c29056e95cd79f3cb19ac456f3bMarco Nelissen if (bestMatch == null || ! mAudioUri.equals(bestMatch.mTableUri)) { 12909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 12919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 129220b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 12939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 12949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // OK, now we need to add this to the database 12959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project values.clear(); 12969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project values.put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, Integer.valueOf(index)); 12979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project values.put(MediaStore.Audio.Playlists.Members.AUDIO_ID, Long.valueOf(bestMatch.mRowId)); 12989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaProvider.insert(uri, values); 12999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (RemoteException e) { 13009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "RemoteException in MediaScanner.addPlayListEntry()", e); 13019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 13029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 13059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 130620b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 13079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void processM3uPlayList(String path, String playListDirectory, Uri uri, ContentValues values) { 13089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project BufferedReader reader = null; 13099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 13109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project File f = new File(path); 13119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (f.exists()) { 13129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project reader = new BufferedReader( 13139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project new InputStreamReader(new FileInputStream(f)), 8192); 13149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String line = reader.readLine(); 13159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int index = 0; 13169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (line != null) { 13179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // ignore comment lines, which begin with '#' 13189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (line.length() > 0 && line.charAt(0) != '#') { 13199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project values.clear(); 13209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (addPlayListEntry(line, playListDirectory, uri, values, index)) 13219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project index++; 13229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project line = reader.readLine(); 13249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 13279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "IOException in MediaScanner.processM3uPlayList()", e); 13289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 13299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 13309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (reader != null) 13319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project reader.close(); 13329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 13339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "IOException in MediaScanner.processM3uPlayList()", e); 13349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void processPlsPlayList(String path, String playListDirectory, Uri uri, ContentValues values) { 13399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project BufferedReader reader = null; 13409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 13419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project File f = new File(path); 13429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (f.exists()) { 13439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project reader = new BufferedReader( 13449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project new InputStreamReader(new FileInputStream(f)), 8192); 13459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String line = reader.readLine(); 13469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int index = 0; 13479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (line != null) { 13489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // ignore comment lines, which begin with '#' 13499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (line.startsWith("File")) { 13509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int equals = line.indexOf('='); 13519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (equals > 0) { 13529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project values.clear(); 13539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (addPlayListEntry(line.substring(equals + 1), playListDirectory, uri, values, index)) 13549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project index++; 13559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project line = reader.readLine(); 13589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 13619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "IOException in MediaScanner.processPlsPlayList()", e); 13629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 13639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 13649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (reader != null) 13659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project reader.close(); 13669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 13679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "IOException in MediaScanner.processPlsPlayList()", e); 13689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project class WplHandler implements ElementListener { 13739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final ContentHandler handler; 13759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String playListDirectory; 13769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Uri uri; 13779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ContentValues values = new ContentValues(); 13789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int index = 0; 13799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public WplHandler(String playListDirectory, Uri uri) { 13819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this.playListDirectory = playListDirectory; 13829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this.uri = uri; 138320b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 13849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project RootElement root = new RootElement("smil"); 13859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Element body = root.getChild("body"); 13869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Element seq = body.getChild("seq"); 13879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Element media = seq.getChild("media"); 13889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project media.setElementListener(this); 13899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this.handler = root.getContentHandler(); 13919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void start(Attributes attributes) { 13949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String path = attributes.getValue("", "src"); 13959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (path != null) { 13969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project values.clear(); 13979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (addPlayListEntry(path, playListDirectory, uri, values, index)) { 13989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project index++; 13999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void end() { 14049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ContentHandler getContentHandler() { 14079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return handler; 14089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void processWplPlayList(String path, String playListDirectory, Uri uri) { 14129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project FileInputStream fis = null; 14139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 14149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project File f = new File(path); 14159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (f.exists()) { 14169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fis = new FileInputStream(f); 14179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Xml.parse(fis, Xml.findEncodingByName("UTF-8"), new WplHandler(playListDirectory, uri).getContentHandler()); 14199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (SAXException e) { 14219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project e.printStackTrace(); 14229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 14239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project e.printStackTrace(); 14249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 14259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 14269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (fis != null) 14279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project fis.close(); 14289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IOException e) { 14299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "IOException in MediaScanner.processWplPlayList()", e); 14309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 143320b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 14349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void processPlayLists() throws RemoteException { 14359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Iterator<FileCacheEntry> iterator = mPlayLists.iterator(); 14369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (iterator.hasNext()) { 14379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project FileCacheEntry entry = iterator.next(); 143820b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync String path = entry.mPath; 14399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // only process playlist files if they are new or have been modified since the last scan 14419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (entry.mLastModifiedChanged) { 14429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ContentValues values = new ContentValues(); 14439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int lastSlash = path.lastIndexOf('/'); 14449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (lastSlash < 0) throw new IllegalArgumentException("bad path " + path); 14459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Uri uri, membersUri; 14469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long rowId = entry.mRowId; 14479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (rowId == 0) { 14489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Create a new playlist 144920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 14509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int lastDot = path.lastIndexOf('.'); 14519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String name = (lastDot < 0 ? path.substring(lastSlash + 1) : path.substring(lastSlash + 1, lastDot)); 14529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project values.put(MediaStore.Audio.Playlists.NAME, name); 14539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project values.put(MediaStore.Audio.Playlists.DATA, path); 14549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project values.put(MediaStore.Audio.Playlists.DATE_MODIFIED, entry.mLastModified); 14559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project uri = mMediaProvider.insert(mPlaylistsUri, values); 14569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project rowId = ContentUris.parseId(uri); 14579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project membersUri = Uri.withAppendedPath(uri, Playlists.Members.CONTENT_DIRECTORY); 14589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 14599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project uri = ContentUris.withAppendedId(mPlaylistsUri, rowId); 146020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 14619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // update lastModified value of existing playlist 14629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project values.put(MediaStore.Audio.Playlists.DATE_MODIFIED, entry.mLastModified); 14639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaProvider.update(uri, values, null, null); 14649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // delete members of existing playlist 14669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project membersUri = Uri.withAppendedPath(uri, Playlists.Members.CONTENT_DIRECTORY); 14679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaProvider.delete(membersUri, null, null); 14689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 146920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 14709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String playListDirectory = path.substring(0, lastSlash + 1); 14719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MediaFile.MediaFileType mediaFileType = MediaFile.getFileType(path); 14729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int fileType = (mediaFileType == null ? 0 : mediaFileType.fileType); 14739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (fileType == MediaFile.FILE_TYPE_M3U) 14759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project processM3uPlayList(path, playListDirectory, membersUri, values); 14769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else if (fileType == MediaFile.FILE_TYPE_PLS) 14779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project processPlsPlayList(path, playListDirectory, membersUri, values); 14789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project else if (fileType == MediaFile.FILE_TYPE_WPL) 14799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project processWplPlayList(path, playListDirectory, membersUri); 148020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 14819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Cursor cursor = mMediaProvider.query(membersUri, PLAYLIST_MEMBERS_PROJECTION, null, 14829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project null, null); 14839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 14849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (cursor == null || cursor.getCount() == 0) { 14859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.d(TAG, "playlist is empty - deleting"); 14869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaProvider.delete(uri, null, null); 14879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 14899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (cursor != null) cursor.close(); 14909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 149420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 1495c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood private native void processDirectory(String path, MediaScannerClient client); 14969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private native void processFile(String path, String mimeType, MediaScannerClient client); 14979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public native void setLocale(String locale); 149820b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync 14999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public native byte[] extractAlbumArt(FileDescriptor fd); 15009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15014935d05eaa306cef88cf0ab13eca386f270409ecMarco Nelissen private static native final void native_init(); 15029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private native final void native_setup(); 15039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private native final void native_finalize(); 15049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 150520b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync protected void finalize() { 15069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.getContentResolver().releaseProvider(mMediaProvider); 150720b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync native_finalize(); 15089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1510