19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.media;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19bfcb22a207499c7ecd4aef9bea2ac778d8be8fc8Marco Nelissenimport org.xml.sax.Attributes;
20bfcb22a207499c7ecd4aef9bea2ac778d8be8fc8Marco Nelissenimport org.xml.sax.ContentHandler;
21bfcb22a207499c7ecd4aef9bea2ac778d8be8fc8Marco Nelissenimport org.xml.sax.SAXException;
22bfcb22a207499c7ecd4aef9bea2ac778d8be8fc8Marco Nelissen
23bfcb22a207499c7ecd4aef9bea2ac778d8be8fc8Marco Nelissenimport android.content.ContentUris;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ContentValues;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.IContentProvider;
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.database.Cursor;
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.database.SQLException;
295d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wangimport android.drm.DrmManagerClient;
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.BitmapFactory;
310cd0136d440cf6ad9d5fab430269116786e671ecMike Lockwoodimport android.mtp.MtpConstants;
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.Uri;
33250528e5b2362cb7b6749afb331acd8226f67744Mike Lockwoodimport android.os.Environment;
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.RemoteException;
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemProperties;
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.MediaStore;
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.MediaStore.Audio;
380b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissenimport android.provider.MediaStore.Audio.Playlists;
39c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwoodimport android.provider.MediaStore.Files;
400b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissenimport android.provider.MediaStore.Files.FileColumns;
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.MediaStore.Images;
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.MediaStore.Video;
430b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissenimport android.provider.Settings;
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.sax.Element;
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.sax.ElementListener;
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.sax.RootElement;
4734385d352da19805ae948215e2edbeedd16b7941Elliott Hughesimport android.system.ErrnoException;
4834385d352da19805ae948215e2edbeedd16b7941Elliott Hughesimport android.system.Os;
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.TextUtils;
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log;
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Xml;
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
53bfcb22a207499c7ecd4aef9bea2ac778d8be8fc8Marco Nelissenimport java.io.BufferedReader;
54bfcb22a207499c7ecd4aef9bea2ac778d8be8fc8Marco Nelissenimport java.io.File;
55bfcb22a207499c7ecd4aef9bea2ac778d8be8fc8Marco Nelissenimport java.io.FileDescriptor;
56bfcb22a207499c7ecd4aef9bea2ac778d8be8fc8Marco Nelissenimport java.io.FileInputStream;
57bfcb22a207499c7ecd4aef9bea2ac778d8be8fc8Marco Nelissenimport java.io.IOException;
58bfcb22a207499c7ecd4aef9bea2ac778d8be8fc8Marco Nelissenimport java.io.InputStreamReader;
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList;
6093a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissenimport java.util.HashMap;
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.HashSet;
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Iterator;
63ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissenimport java.util.Locale;
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
6677f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * Internal service helper that no-one should use directly.
6720b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync *
6877f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * The way the scan currently works is:
6977f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * - The Java MediaScannerService creates a MediaScanner (this class), and calls
7077f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen *   MediaScanner.scanDirectories on it.
7177f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * - scanDirectories() calls the native processDirectory() for each of the specified directories.
7277f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * - the processDirectory() JNI method wraps the provided mediascanner client in a native
7377f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen *   'MyMediaScannerClient' class, then calls processDirectory() on the native MediaScanner
7477f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen *   object (which got created when the Java MediaScanner was created).
757ae82ce1fd54103bb87b8a0593a4228c94b1d6f9James Dong * - native MediaScanner.processDirectory() calls
7677f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen *   doProcessDirectory(), which recurses over the folder, and calls
7777f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen *   native MyMediaScannerClient.scanFile() for every file whose extension matches.
7877f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * - native MyMediaScannerClient.scanFile() calls back on Java MediaScannerClient.scanFile,
7977f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen *   which calls doScanFile, which after some setup calls back down to native code, calling
8077f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen *   MediaScanner.processFile().
8177f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * - MediaScanner.processFile() calls one of several methods, depending on the type of the
8277f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen *   file: parseMP3, parseMP4, parseMidi, parseOgg or parseWMA.
8377f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * - each of these methods gets metadata key/value pairs from the file, and repeatedly
8477f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen *   calls native MyMediaScannerClient.handleStringTag, which calls back up to its Java
8577f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen *   counterparts in this file.
8677f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * - Java handleStringTag() gathers the key/value pairs that it's interested in.
8777f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * - once processFile returns and we're back in Java code in doScanFile(), it calls
8877f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen *   Java MyMediaScannerClient.endFile(), which takes all the data that's been
8977f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen *   gathered and inserts an entry in to the database.
9077f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen *
9177f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * In summary:
9277f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * Java MediaScannerService calls
9377f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * Java MediaScanner scanDirectories, which calls
9477f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * Java MediaScanner processDirectory (native method), which calls
9577f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * native MediaScanner processDirectory, which calls
9677f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * native MyMediaScannerClient scanFile, which calls
9777f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * Java MyMediaScannerClient scanFile, which calls
9877f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * Java MediaScannerClient doScanFile, which calls
9977f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * Java MediaScanner processFile (native method), which calls
10077f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * native MediaScanner processFile, which calls
10177f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * native parseMP3, parseMP4, parseMidi, parseOgg or parseWMA, which calls
10277f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * native MyMediaScanner handleStringTag, which calls
10377f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * Java MyMediaScanner handleStringTag.
10477f2c4c1f9d1b8b9266a18e8e28fcabdf6599399Marco Nelissen * Once MediaScanner processFile returns, an entry is inserted in to the database.
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
106af16d0b30e89f31b7617424c8706553ff571d08dMike Lockwood * The MediaScanner class is not thread-safe, so it should only be used in a single threaded manner.
107af16d0b30e89f31b7617424c8706553ff571d08dMike Lockwood *
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@hide}
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class MediaScanner
11120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync{
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static {
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        System.loadLibrary("media_jni");
1144935d05eaa306cef88cf0ab13eca386f270409ecMarco Nelissen        native_init();
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final static String TAG = "MediaScanner";
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
119d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood    private static final String[] FILES_PRESCAN_PROJECTION = new String[] {
120c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood            Files.FileColumns._ID, // 0
121c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood            Files.FileColumns.DATA, // 1
122d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood            Files.FileColumns.FORMAT, // 2
123d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood            Files.FileColumns.DATE_MODIFIED, // 3
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
12520b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
1266458935331ccfacb4cccc50d6b893947febae687Mike Lockwood    private static final String[] ID_PROJECTION = new String[] {
1276458935331ccfacb4cccc50d6b893947febae687Mike Lockwood            Files.FileColumns._ID,
1286458935331ccfacb4cccc50d6b893947febae687Mike Lockwood    };
1296458935331ccfacb4cccc50d6b893947febae687Mike Lockwood
130d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood    private static final int FILES_PRESCAN_ID_COLUMN_INDEX = 0;
131d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood    private static final int FILES_PRESCAN_PATH_COLUMN_INDEX = 1;
132d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood    private static final int FILES_PRESCAN_FORMAT_COLUMN_INDEX = 2;
133d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood    private static final int FILES_PRESCAN_DATE_MODIFIED_COLUMN_INDEX = 3;
134d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String[] PLAYLIST_MEMBERS_PROJECTION = new String[] {
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Audio.Playlists.Members.PLAYLIST_ID, // 0
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     };
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int ID_PLAYLISTS_COLUMN_INDEX = 0;
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int PATH_PLAYLISTS_COLUMN_INDEX = 1;
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int DATE_MODIFIED_PLAYLISTS_COLUMN_INDEX = 2;
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String RINGTONES_DIR = "/ringtones/";
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String NOTIFICATIONS_DIR = "/notifications/";
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String ALARMS_DIR = "/alarms/";
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String MUSIC_DIR = "/music/";
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String PODCAST_DIR = "/podcasts/";
14820b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String[] ID3_GENRES = {
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // ID3v1 Genres
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Blues",
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Classic Rock",
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Country",
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Dance",
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Disco",
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Funk",
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Grunge",
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Hip-Hop",
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Jazz",
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Metal",
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "New Age",
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Oldies",
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Other",
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Pop",
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "R&B",
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Rap",
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Reggae",
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Rock",
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Techno",
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Industrial",
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Alternative",
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Ska",
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Death Metal",
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Pranks",
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Soundtrack",
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Euro-Techno",
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Ambient",
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Trip-Hop",
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Vocal",
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Jazz+Funk",
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Fusion",
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Trance",
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Classical",
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Instrumental",
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Acid",
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "House",
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Game",
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Sound Clip",
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Gospel",
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Noise",
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "AlternRock",
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Bass",
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Soul",
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Punk",
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Space",
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Meditative",
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Instrumental Pop",
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Instrumental Rock",
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Ethnic",
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Gothic",
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Darkwave",
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Techno-Industrial",
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Electronic",
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Pop-Folk",
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Eurodance",
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Dream",
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Southern Rock",
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Comedy",
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Cult",
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Gangsta",
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Top 40",
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Christian Rap",
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Pop/Funk",
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Jungle",
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Native American",
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Cabaret",
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "New Wave",
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Psychadelic",
2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Rave",
2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Showtunes",
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Trailer",
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Lo-Fi",
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Tribal",
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Acid Punk",
2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Acid Jazz",
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Polka",
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Retro",
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Musical",
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Rock & Roll",
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Hard Rock",
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // The following genres are Winamp extensions
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Folk",
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Folk-Rock",
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "National Folk",
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Swing",
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Fast Fusion",
2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Bebob",
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Latin",
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Revival",
2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Celtic",
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Bluegrass",
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Avantgarde",
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Gothic Rock",
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Progressive Rock",
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Psychedelic Rock",
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Symphonic Rock",
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Slow Rock",
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Big Band",
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Chorus",
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Easy Listening",
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Acoustic",
2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Humour",
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Speech",
2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Chanson",
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Opera",
2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Chamber Music",
2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Sonata",
2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Symphony",
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Booty Bass",
2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Primus",
2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Porn Groove",
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Satire",
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Slow Jam",
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Club",
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Tango",
2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Samba",
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Folklore",
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Ballad",
2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Power Ballad",
2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Rhythmic Soul",
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Freestyle",
2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Duet",
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Punk Rock",
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Drum Solo",
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "A capella",
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Euro-House",
277cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen        "Dance Hall",
278cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen        // The following ones seem to be fairly widely supported as well
279cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen        "Goa",
280cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen        "Drum & Bass",
281cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen        "Club-House",
282cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen        "Hardcore",
283cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen        "Terror",
284cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen        "Indie",
285cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen        "Britpop",
286c3ea477e2111f199d10341b121791cb2ec91eca3Johan Redestig        null,
287cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen        "Polsk Punk",
288cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen        "Beat",
289cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen        "Christian Gangsta",
290cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen        "Heavy Metal",
291cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen        "Black Metal",
292cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen        "Crossover",
293cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen        "Contemporary Christian",
294cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen        "Christian Rock",
295cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen        "Merengue",
296cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen        "Salsa",
297cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen        "Thrash Metal",
298cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen        "Anime",
299cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen        "JPop",
300cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen        "Synthpop",
301cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen        // 148 and up don't seem to have been defined yet.
3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
304075e9a19ce645752f8282bc19c91b25978a7dc52Ashok Bhat    private long mNativeContext;
3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Context mContext;
30635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn    private String mPackageName;
3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private IContentProvider mMediaProvider;
3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Uri mAudioUri;
3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Uri mVideoUri;
3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Uri mImagesUri;
3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Uri mThumbsUri;
3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Uri mPlaylistsUri;
313c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood    private Uri mFilesUri;
3148ad76fa7a644c10abb7b95398fdb8a84bd723619Marco Nelissen    private Uri mFilesUriNoNotify;
31543b076bb75e86fbb34cbe36aa0298c7a647121ffMike Lockwood    private boolean mProcessPlaylists, mProcessGenres;
316d815f79766984fce499e147ecbacc01914683f74Mike Lockwood    private int mMtpObjectHandle;
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
318250528e5b2362cb7b6749afb331acd8226f67744Mike Lockwood    private final String mExternalStoragePath;
319c861411d4bae0912054ff54c3efee90ae2db6db9Marco Nelissen    private final boolean mExternalIsEmulated;
320250528e5b2362cb7b6749afb331acd8226f67744Mike Lockwood
321d6b3e0cc36cbe28c8d194b63227df37c76af7efaMarco Nelissen    /** whether to use bulk inserts or individual inserts for each item */
322d6b3e0cc36cbe28c8d194b63227df37c76af7efaMarco Nelissen    private static final boolean ENABLE_BULK_INSERTS = true;
3233410b4656505673c72da558dcfec94d7b135e760Mike Lockwood
3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // used when scanning the image database so we know whether we have to prune
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // old thumbnail files
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mOriginalCount;
327bcbddd9342ee5ef48617ce7dcca6c505df3fcf08Marco Nelissen    /** Whether the database had any entries in it before the scan started */
328bcbddd9342ee5ef48617ce7dcca6c505df3fcf08Marco Nelissen    private boolean mWasEmptyPriorToScan = false;
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Whether the scanner has set a default sound for the ringer ringtone. */
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mDefaultRingtoneSet;
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Whether the scanner has set a default sound for the notification ringtone. */
3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mDefaultNotificationSet;
3333156bb00dd3ab3d6ec732bb6a64a2e84d08c34f0Patrick Scott    /** Whether the scanner has set a default sound for the alarm ringtone. */
3343156bb00dd3ab3d6ec732bb6a64a2e84d08c34f0Patrick Scott    private boolean mDefaultAlarmSet;
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** The filename for the default sound for the ringer ringtone. */
3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private String mDefaultRingtoneFilename;
3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** The filename for the default sound for the notification ringtone. */
3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private String mDefaultNotificationFilename;
3393156bb00dd3ab3d6ec732bb6a64a2e84d08c34f0Patrick Scott    /** The filename for the default sound for the alarm ringtone. */
3403156bb00dd3ab3d6ec732bb6a64a2e84d08c34f0Patrick Scott    private String mDefaultAlarmAlertFilename;
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The prefix for system properties that define the default sound for
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * ringtones. Concatenate the name of the setting from Settings
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * to get the full system property.
3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String DEFAULT_RINGTONE_PROPERTY_PREFIX = "ro.config.";
34720b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // set to true if file path comparisons should be case insensitive.
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // this should be set when scanning files on a case insensitive file system.
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mCaseInsensitivePaths;
35120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
35230c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten    private final BitmapFactory.Options mBitmapOptions = new BitmapFactory.Options();
3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
35458ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen    private static class FileEntry {
3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long mRowId;
3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String mPath;
3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long mLastModified;
358d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood        int mFormat;
3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean mLastModifiedChanged;
36020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
36158ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen        FileEntry(long rowId, String path, long lastModified, int format) {
3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mRowId = rowId;
3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mPath = path;
3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mLastModified = lastModified;
365d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood            mFormat = format;
3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mLastModifiedChanged = false;
3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String toString() {
3713e5e8055942ee8179675b8ed11d40ca12dbe42e6Marco Nelissen            return mPath + " mRowId: " + mRowId;
3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
37420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
3750b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen    private static class PlaylistEntry {
3760b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen        String path;
3770b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen        long bestmatchid;
3780b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen        int bestmatchlevel;
3790b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen    }
3800b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen
3810b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen    private ArrayList<PlaylistEntry> mPlaylistEntries = new ArrayList<PlaylistEntry>();
3820b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen
3838e2ed8d512ade2ea481b3a292556782b17a74674Dongwon Kang    private MediaInserter mMediaInserter;
384bd682b040833fce9e212c00c395b32bec7050f87Mike Lockwood
38558ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen    private ArrayList<FileEntry> mPlayLists;
3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3875d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang    private DrmManagerClient mDrmManagerClient = null;
3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public MediaScanner(Context c) {
3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        native_setup();
3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext = c;
39235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        mPackageName = c.getPackageName();
3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mBitmapOptions.inSampleSize = 1;
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mBitmapOptions.inJustDecodeBounds = true;
39520b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setDefaultRingtoneFileNames();
397250528e5b2362cb7b6749afb331acd8226f67744Mike Lockwood
398250528e5b2362cb7b6749afb331acd8226f67744Mike Lockwood        mExternalStoragePath = Environment.getExternalStorageDirectory().getAbsolutePath();
399c861411d4bae0912054ff54c3efee90ae2db6db9Marco Nelissen        mExternalIsEmulated = Environment.isExternalStorageEmulated();
400ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen        //mClient.testGenreNameConverter();
4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void setDefaultRingtoneFileNames() {
4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mDefaultRingtoneFilename = SystemProperties.get(DEFAULT_RINGTONE_PROPERTY_PREFIX
4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                + Settings.System.RINGTONE);
4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mDefaultNotificationFilename = SystemProperties.get(DEFAULT_RINGTONE_PROPERTY_PREFIX
4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                + Settings.System.NOTIFICATION_SOUND);
4083156bb00dd3ab3d6ec732bb6a64a2e84d08c34f0Patrick Scott        mDefaultAlarmAlertFilename = SystemProperties.get(DEFAULT_RINGTONE_PROPERTY_PREFIX
4093156bb00dd3ab3d6ec732bb6a64a2e84d08c34f0Patrick Scott                + Settings.System.ALARM_ALERT);
4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
41120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
41230c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten    private final MyMediaScannerClient mClient = new MyMediaScannerClient();
41320b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
414e4eb4d9de37a8e9ed6f43a5f7deccf88f28bfc8bMarco Nelissen    private boolean isDrmEnabled() {
4151f89c4f9f8df5d7125221250993ba1e853ed9fedGloria Wang        String prop = SystemProperties.get("drm.service.enabled");
416e4eb4d9de37a8e9ed6f43a5f7deccf88f28bfc8bMarco Nelissen        return prop != null && prop.equals("true");
417e4eb4d9de37a8e9ed6f43a5f7deccf88f28bfc8bMarco Nelissen    }
418fbc4939d2b51d511858846363bf02c7c9f851ed2Mike Lockwood
4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private class MyMediaScannerClient implements MediaScannerClient {
42020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private String mArtist;
4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private String mAlbumArtist;    // use this if mArtist is missing
4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private String mAlbum;
4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private String mTitle;
4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private String mComposer;
4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private String mGenre;
4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private String mMimeType;
4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private int mFileType;
4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private int mTrack;
4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private int mYear;
4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private int mDuration;
4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private String mPath;
4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private long mLastModified;
4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private long mFileSize;
435c9706f0262a2f399f95e0d78ba2b7616e08d0069Sahil Sachdeva        private String mWriter;
436f679ba7d944a403fbdc77926c44978ffd5161f2dMarco Nelissen        private int mCompilation;
43782428a862f325238cfb5646bbd65de3f1a11e7ccGloria Wang        private boolean mIsDrm;
438997354e4b4a9666cedd62282471e97822affced9Mike Lockwood        private boolean mNoMedia;   // flag to suppress file from appearing in media tables
439e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang        private int mWidth;
440e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang        private int mHeight;
44120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
44258ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen        public FileEntry beginFile(String path, String mimeType, long lastModified,
443997354e4b4a9666cedd62282471e97822affced9Mike Lockwood                long fileSize, boolean isDirectory, boolean noMedia) {
444076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood            mMimeType = mimeType;
445076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood            mFileType = 0;
446076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood            mFileSize = fileSize;
44759c14048bfc0a210077192410afa28ed6f85daa0Erik Almqvist            mIsDrm = false;
44820b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
449076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood            if (!isDirectory) {
450ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood                if (!noMedia && isNoMediaFile(path)) {
451ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood                    noMedia = true;
4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
453997354e4b4a9666cedd62282471e97822affced9Mike Lockwood                mNoMedia = noMedia;
45420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
455076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood                // try mimeType first, if it is specified
456076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood                if (mimeType != null) {
457076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood                    mFileType = MediaFile.getFileTypeForMimeType(mimeType);
458076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood                }
4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
460076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood                // if mimeType was not specified, compute file type based on file extension.
461076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood                if (mFileType == 0) {
462076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood                    MediaFile.MediaFileType mediaFileType = MediaFile.getFileType(path);
463076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood                    if (mediaFileType != null) {
464076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood                        mFileType = mediaFileType.fileType;
465076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood                        if (mMimeType == null) {
466076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood                            mMimeType = mediaFileType.mimeType;
467076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood                        }
468858caeaaa1db4076565e6df06b2b2721ec453c4eMike Lockwood                    }
4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
47020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
471076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood                if (isDrmEnabled() && MediaFile.isDrmFileType(mFileType)) {
472076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood                    mFileType = getFileTypeFromDrm(path);
473076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood                }
4745d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang            }
4755d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang
47658ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen            FileEntry entry = makeEntryFor(path);
477a8a656b0c595fa876a387a91f8813f88a2d3abe7Marco Nelissen            // add some slack to avoid a rounding error
478a8a656b0c595fa876a387a91f8813f88a2d3abe7Marco Nelissen            long delta = (entry != null) ? (lastModified - entry.mLastModified) : 0;
479a8a656b0c595fa876a387a91f8813f88a2d3abe7Marco Nelissen            boolean wasModified = delta > 1 || delta < -1;
480a8a656b0c595fa876a387a91f8813f88a2d3abe7Marco Nelissen            if (entry == null || wasModified) {
481a8a656b0c595fa876a387a91f8813f88a2d3abe7Marco Nelissen                if (wasModified) {
482a8a656b0c595fa876a387a91f8813f88a2d3abe7Marco Nelissen                    entry.mLastModified = lastModified;
483a8a656b0c595fa876a387a91f8813f88a2d3abe7Marco Nelissen                } else {
48458ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                    entry = new FileEntry(0, path, lastModified,
485a8a656b0c595fa876a387a91f8813f88a2d3abe7Marco Nelissen                            (isDirectory ? MtpConstants.FORMAT_ASSOCIATION : 0));
486a8a656b0c595fa876a387a91f8813f88a2d3abe7Marco Nelissen                }
4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                entry.mLastModifiedChanged = true;
4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
48920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mProcessPlaylists && MediaFile.isPlayListFileType(mFileType)) {
4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mPlayLists.add(entry);
4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // we don't process playlists in the main scan, so return null
4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return null;
4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
49520b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // clear all the metadata
4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mArtist = null;
4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mAlbumArtist = null;
4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mAlbum = null;
5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mTitle = null;
5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mComposer = null;
5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mGenre = null;
5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mTrack = 0;
5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mYear = 0;
5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mDuration = 0;
5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mPath = path;
5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mLastModified = lastModified;
508c9706f0262a2f399f95e0d78ba2b7616e08d0069Sahil Sachdeva            mWriter = null;
509f679ba7d944a403fbdc77926c44978ffd5161f2dMarco Nelissen            mCompilation = 0;
510e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang            mWidth = 0;
511e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang            mHeight = 0;
51220b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return entry;
5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
51520b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
516bcbddd9342ee5ef48617ce7dcca6c505df3fcf08Marco Nelissen        @Override
517997354e4b4a9666cedd62282471e97822affced9Mike Lockwood        public void scanFile(String path, long lastModified, long fileSize,
518997354e4b4a9666cedd62282471e97822affced9Mike Lockwood                boolean isDirectory, boolean noMedia) {
51900c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen            // This is the callback funtion from native codes.
52000c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen            // Log.v(TAG, "scanFile: "+path);
521997354e4b4a9666cedd62282471e97822affced9Mike Lockwood            doScanFile(path, null, lastModified, fileSize, isDirectory, false, noMedia);
5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
524c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood        public Uri doScanFile(String path, String mimeType, long lastModified,
525997354e4b4a9666cedd62282471e97822affced9Mike Lockwood                long fileSize, boolean isDirectory, boolean scanAlways, boolean noMedia) {
5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Uri result = null;
5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project//            long t1 = System.currentTimeMillis();
5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
52958ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                FileEntry entry = beginFile(path, mimeType, lastModified,
530997354e4b4a9666cedd62282471e97822affced9Mike Lockwood                        fileSize, isDirectory, noMedia);
53181e85bbf671f228600fba059e30cb22565bcfe9dMarco Nelissen
53281e85bbf671f228600fba059e30cb22565bcfe9dMarco Nelissen                // if this file was just inserted via mtp, set the rowid to zero
53381e85bbf671f228600fba059e30cb22565bcfe9dMarco Nelissen                // (even though it already exists in the database), to trigger
53481e85bbf671f228600fba059e30cb22565bcfe9dMarco Nelissen                // the correct code path for updating its entry
53581e85bbf671f228600fba059e30cb22565bcfe9dMarco Nelissen                if (mMtpObjectHandle != 0) {
53681e85bbf671f228600fba059e30cb22565bcfe9dMarco Nelissen                    entry.mRowId = 0;
53781e85bbf671f228600fba059e30cb22565bcfe9dMarco Nelissen                }
5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // rescan for metadata if file was modified since last scan
5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (entry != null && (entry.mLastModifiedChanged || scanAlways)) {
540997354e4b4a9666cedd62282471e97822affced9Mike Lockwood                    if (noMedia) {
541997354e4b4a9666cedd62282471e97822affced9Mike Lockwood                        result = endFile(entry, false, false, false, false, false);
542997354e4b4a9666cedd62282471e97822affced9Mike Lockwood                    } else {
543dcb1a58cf9d66b36de825dae2fa0cb0529e60680Elliott Hughes                        String lowpath = path.toLowerCase(Locale.ROOT);
544997354e4b4a9666cedd62282471e97822affced9Mike Lockwood                        boolean ringtones = (lowpath.indexOf(RINGTONES_DIR) > 0);
545997354e4b4a9666cedd62282471e97822affced9Mike Lockwood                        boolean notifications = (lowpath.indexOf(NOTIFICATIONS_DIR) > 0);
546997354e4b4a9666cedd62282471e97822affced9Mike Lockwood                        boolean alarms = (lowpath.indexOf(ALARMS_DIR) > 0);
547997354e4b4a9666cedd62282471e97822affced9Mike Lockwood                        boolean podcasts = (lowpath.indexOf(PODCAST_DIR) > 0);
548997354e4b4a9666cedd62282471e97822affced9Mike Lockwood                        boolean music = (lowpath.indexOf(MUSIC_DIR) > 0) ||
549997354e4b4a9666cedd62282471e97822affced9Mike Lockwood                            (!ringtones && !notifications && !alarms && !podcasts);
550997354e4b4a9666cedd62282471e97822affced9Mike Lockwood
551c861411d4bae0912054ff54c3efee90ae2db6db9Marco Nelissen                        boolean isaudio = MediaFile.isAudioFileType(mFileType);
552c861411d4bae0912054ff54c3efee90ae2db6db9Marco Nelissen                        boolean isvideo = MediaFile.isVideoFileType(mFileType);
553c861411d4bae0912054ff54c3efee90ae2db6db9Marco Nelissen                        boolean isimage = MediaFile.isImageFileType(mFileType);
554c861411d4bae0912054ff54c3efee90ae2db6db9Marco Nelissen
555c861411d4bae0912054ff54c3efee90ae2db6db9Marco Nelissen                        if (isaudio || isvideo || isimage) {
556c861411d4bae0912054ff54c3efee90ae2db6db9Marco Nelissen                            if (mExternalIsEmulated && path.startsWith(mExternalStoragePath)) {
557c861411d4bae0912054ff54c3efee90ae2db6db9Marco Nelissen                                // try to rewrite the path to bypass the sd card fuse layer
558c861411d4bae0912054ff54c3efee90ae2db6db9Marco Nelissen                                String directPath = Environment.getMediaStorageDirectory() +
559c861411d4bae0912054ff54c3efee90ae2db6db9Marco Nelissen                                        path.substring(mExternalStoragePath.length());
560c861411d4bae0912054ff54c3efee90ae2db6db9Marco Nelissen                                File f = new File(directPath);
561c861411d4bae0912054ff54c3efee90ae2db6db9Marco Nelissen                                if (f.exists()) {
562c861411d4bae0912054ff54c3efee90ae2db6db9Marco Nelissen                                    path = directPath;
563c861411d4bae0912054ff54c3efee90ae2db6db9Marco Nelissen                                }
564c861411d4bae0912054ff54c3efee90ae2db6db9Marco Nelissen                            }
565c861411d4bae0912054ff54c3efee90ae2db6db9Marco Nelissen                        }
566c861411d4bae0912054ff54c3efee90ae2db6db9Marco Nelissen
567997354e4b4a9666cedd62282471e97822affced9Mike Lockwood                        // we only extract metadata for audio and video files
568c861411d4bae0912054ff54c3efee90ae2db6db9Marco Nelissen                        if (isaudio || isvideo) {
569997354e4b4a9666cedd62282471e97822affced9Mike Lockwood                            processFile(path, mimeType, this);
570997354e4b4a9666cedd62282471e97822affced9Mike Lockwood                        }
57120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
572c861411d4bae0912054ff54c3efee90ae2db6db9Marco Nelissen                        if (isimage) {
573e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang                            processImageFile(path);
574e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang                        }
575e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang
576997354e4b4a9666cedd62282471e97822affced9Mike Lockwood                        result = endFile(entry, ringtones, notifications, alarms, music, podcasts);
577997354e4b4a9666cedd62282471e97822affced9Mike Lockwood                    }
5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (RemoteException e) {
5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Log.e(TAG, "RemoteException in MediaScanner.scanFile()", e);
5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project//            long t2 = System.currentTimeMillis();
5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project//            Log.v(TAG, "scanFile: " + path + " took " + (t2-t1));
5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return result;
5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private int parseSubstring(String s, int start, int defaultValue) {
5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int length = s.length();
5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (start == length) return defaultValue;
5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            char ch = s.charAt(start++);
5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // return defaultValue if we have no integer at all
5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (ch < '0' || ch > '9') return defaultValue;
59420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int result = ch - '0';
5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            while (start < length) {
5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ch = s.charAt(start++);
5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (ch < '0' || ch > '9') return result;
5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                result = result * 10 + (ch - '0');
6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
60120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return result;
60320b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync        }
60420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void handleStringTag(String name, String value) {
6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (name.equalsIgnoreCase("title") || name.startsWith("title;")) {
60773bb511adee5444ecd041146fbbd3677fb635949Marco Nelissen                // Don't trim() here, to preserve the special \001 character
60873bb511adee5444ecd041146fbbd3677fb635949Marco Nelissen                // used to force sorting. The media provider will trim() before
60973bb511adee5444ecd041146fbbd3677fb635949Marco Nelissen                // inserting the title in to the database.
61073bb511adee5444ecd041146fbbd3677fb635949Marco Nelissen                mTitle = value;
6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (name.equalsIgnoreCase("artist") || name.startsWith("artist;")) {
6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mArtist = value.trim();
613ed8188711a794867b47d21bbed3e26827f6c27e3Neel Parekh            } else if (name.equalsIgnoreCase("albumartist") || name.startsWith("albumartist;")
614ed8188711a794867b47d21bbed3e26827f6c27e3Neel Parekh                    || name.equalsIgnoreCase("band") || name.startsWith("band;")) {
6159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mAlbumArtist = value.trim();
6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (name.equalsIgnoreCase("album") || name.startsWith("album;")) {
6179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mAlbum = value.trim();
6189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (name.equalsIgnoreCase("composer") || name.startsWith("composer;")) {
6199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mComposer = value.trim();
62043b076bb75e86fbb34cbe36aa0298c7a647121ffMike Lockwood            } else if (mProcessGenres &&
62143b076bb75e86fbb34cbe36aa0298c7a647121ffMike Lockwood                    (name.equalsIgnoreCase("genre") || name.startsWith("genre;"))) {
622cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen                mGenre = getGenreName(value);
6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (name.equalsIgnoreCase("year") || name.startsWith("year;")) {
6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mYear = parseSubstring(value, 0, 0);
6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (name.equalsIgnoreCase("tracknumber") || name.startsWith("tracknumber;")) {
6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // track number might be of the form "2/12"
6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // we just read the number before the slash
6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int num = parseSubstring(value, 0, 0);
62920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync                mTrack = (mTrack / 1000) * 1000 + num;
6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (name.equalsIgnoreCase("discnumber") ||
6319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    name.equals("set") || name.startsWith("set;")) {
6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // set number might be of the form "1/3"
6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // we just read the number before the slash
6349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int num = parseSubstring(value, 0, 0);
6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mTrack = (num * 1000) + (mTrack % 1000);
6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (name.equalsIgnoreCase("duration")) {
6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mDuration = parseSubstring(value, 0, 0);
638c9706f0262a2f399f95e0d78ba2b7616e08d0069Sahil Sachdeva            } else if (name.equalsIgnoreCase("writer") || name.startsWith("writer;")) {
639c9706f0262a2f399f95e0d78ba2b7616e08d0069Sahil Sachdeva                mWriter = value.trim();
640f679ba7d944a403fbdc77926c44978ffd5161f2dMarco Nelissen            } else if (name.equalsIgnoreCase("compilation")) {
641f679ba7d944a403fbdc77926c44978ffd5161f2dMarco Nelissen                mCompilation = parseSubstring(value, 0, 0);
64282428a862f325238cfb5646bbd65de3f1a11e7ccGloria Wang            } else if (name.equalsIgnoreCase("isdrm")) {
64382428a862f325238cfb5646bbd65de3f1a11e7ccGloria Wang                mIsDrm = (parseSubstring(value, 0, 0) == 1);
644e313f721ad97ad44666dd066a891acb4ddfa8ab3Marco Nelissen            } else if (name.equalsIgnoreCase("width")) {
645e313f721ad97ad44666dd066a891acb4ddfa8ab3Marco Nelissen                mWidth = parseSubstring(value, 0, 0);
646e313f721ad97ad44666dd066a891acb4ddfa8ab3Marco Nelissen            } else if (name.equalsIgnoreCase("height")) {
647e313f721ad97ad44666dd066a891acb4ddfa8ab3Marco Nelissen                mHeight = parseSubstring(value, 0, 0);
648ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen            } else {
649ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen                //Log.v(TAG, "unknown tag: " + name + " (" + mProcessGenres + ")");
6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
65220b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
653ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen        private boolean convertGenreCode(String input, String expected) {
654ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen            String output = getGenreName(input);
655ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen            if (output.equals(expected)) {
656ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen                return true;
657ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen            } else {
658ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen                Log.d(TAG, "'" + input + "' -> '" + output + "', expected '" + expected + "'");
659ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen                return false;
660ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen            }
661ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen        }
662ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen        private void testGenreNameConverter() {
663ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen            convertGenreCode("2", "Country");
664ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen            convertGenreCode("(2)", "Country");
665ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen            convertGenreCode("(2", "(2");
666ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen            convertGenreCode("2 Foo", "Country");
667ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen            convertGenreCode("(2) Foo", "Country");
668ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen            convertGenreCode("(2 Foo", "(2 Foo");
669ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen            convertGenreCode("2Foo", "2Foo");
670ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen            convertGenreCode("(2)Foo", "Country");
671ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen            convertGenreCode("200 Foo", "Foo");
672ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen            convertGenreCode("(200) Foo", "Foo");
673ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen            convertGenreCode("200Foo", "200Foo");
674ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen            convertGenreCode("(200)Foo", "Foo");
675ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen            convertGenreCode("200)Foo", "200)Foo");
676ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen            convertGenreCode("200) Foo", "200) Foo");
677ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen        }
678ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen
679cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen        public String getGenreName(String genreTagValue) {
680cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen
681cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen            if (genreTagValue == null) {
682cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen                return null;
683cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen            }
684cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen            final int length = genreTagValue.length();
685cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen
686ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen            if (length > 0) {
687ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen                boolean parenthesized = false;
688cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen                StringBuffer number = new StringBuffer();
689ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen                int i = 0;
690ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen                for (; i < length; ++i) {
691cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen                    char c = genreTagValue.charAt(i);
692ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen                    if (i == 0 && c == '(') {
693ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen                        parenthesized = true;
694ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen                    } else if (Character.isDigit(c)) {
695cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen                        number.append(c);
696cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen                    } else {
697cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen                        break;
698cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen                    }
699cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen                }
700ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen                char charAfterNumber = i < length ? genreTagValue.charAt(i) : ' ';
701ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen                if ((parenthesized && charAfterNumber == ')')
702ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen                        || !parenthesized && Character.isWhitespace(charAfterNumber)) {
703cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen                    try {
704cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen                        short genreIndex = Short.parseShort(number.toString());
705cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen                        if (genreIndex >= 0) {
706c3ea477e2111f199d10341b121791cb2ec91eca3Johan Redestig                            if (genreIndex < ID3_GENRES.length && ID3_GENRES[genreIndex] != null) {
707cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen                                return ID3_GENRES[genreIndex];
708cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen                            } else if (genreIndex == 0xFF) {
709cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen                                return null;
710cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen                            } else if (genreIndex < 0xFF && (i + 1) < length) {
711cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen                                // genre is valid but unknown,
712cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen                                // if there is a string after the value we take it
713ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen                                if (parenthesized && charAfterNumber == ')') {
714ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen                                    i++;
715ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen                                }
716ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen                                String ret = genreTagValue.substring(i).trim();
717ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen                                if (ret.length() != 0) {
718ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen                                    return ret;
719ad35f9165e7f2641812a5069de9c3cd3fdd16923Marco Nelissen                                }
720cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen                            } else {
721cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen                                // else return the number, without parentheses
722cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen                                return number.toString();
723cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen                            }
724cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen                        }
725cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen                    } catch (NumberFormatException e) {
726cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen                    }
727cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen                }
728cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen            }
729cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen
730cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen            return genreTagValue;
731cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen        }
732cb613a04c16915f6374c6436b5b37355bce3ed1cMarco Nelissen
733e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang        private void processImageFile(String path) {
734e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang            try {
735e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang                mBitmapOptions.outWidth = 0;
736e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang                mBitmapOptions.outHeight = 0;
737e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang                BitmapFactory.decodeFile(path, mBitmapOptions);
738e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang                mWidth = mBitmapOptions.outWidth;
739e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang                mHeight = mBitmapOptions.outHeight;
740e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang            } catch (Throwable th) {
741e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang                // ignore;
742e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang            }
743e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang        }
744e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang
7459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void setMimeType(String mimeType) {
7461851db6804cbdf8d2c8ede0725e73be6fda0f3c0Marco Nelissen            if ("audio/mp4".equals(mMimeType) &&
7471851db6804cbdf8d2c8ede0725e73be6fda0f3c0Marco Nelissen                    mimeType.startsWith("video")) {
7481851db6804cbdf8d2c8ede0725e73be6fda0f3c0Marco Nelissen                // for feature parity with Donut, we force m4a files to keep the
7491851db6804cbdf8d2c8ede0725e73be6fda0f3c0Marco Nelissen                // audio/mp4 mimetype, even if they are really "enhanced podcasts"
7501851db6804cbdf8d2c8ede0725e73be6fda0f3c0Marco Nelissen                // with a video track
7511851db6804cbdf8d2c8ede0725e73be6fda0f3c0Marco Nelissen                return;
7521851db6804cbdf8d2c8ede0725e73be6fda0f3c0Marco Nelissen            }
7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mMimeType = mimeType;
7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mFileType = MediaFile.getFileTypeForMimeType(mimeType);
7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
75620b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Formats the data into a values array suitable for use with the Media
7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Content Provider.
76020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync         *
7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @return a map of values
7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private ContentValues toValues() {
7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ContentValues map = new ContentValues();
7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            map.put(MediaStore.MediaColumns.DATA, mPath);
7679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            map.put(MediaStore.MediaColumns.TITLE, mTitle);
7689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            map.put(MediaStore.MediaColumns.DATE_MODIFIED, mLastModified);
7699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            map.put(MediaStore.MediaColumns.SIZE, mFileSize);
7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            map.put(MediaStore.MediaColumns.MIME_TYPE, mMimeType);
77182428a862f325238cfb5646bbd65de3f1a11e7ccGloria Wang            map.put(MediaStore.MediaColumns.IS_DRM, mIsDrm);
77220b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
773e313f721ad97ad44666dd066a891acb4ddfa8ab3Marco Nelissen            String resolution = null;
774e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang            if (mWidth > 0 && mHeight > 0) {
775e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang                map.put(MediaStore.MediaColumns.WIDTH, mWidth);
776e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang                map.put(MediaStore.MediaColumns.HEIGHT, mHeight);
777e313f721ad97ad44666dd066a891acb4ddfa8ab3Marco Nelissen                resolution = mWidth + "x" + mHeight;
778e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang            }
779e1bf8efaff42dc33b7a4663f3c9d50d12de81bcbChih-Chung Chang
780e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood            if (!mNoMedia) {
781997354e4b4a9666cedd62282471e97822affced9Mike Lockwood                if (MediaFile.isVideoFileType(mFileType)) {
782997354e4b4a9666cedd62282471e97822affced9Mike Lockwood                    map.put(Video.Media.ARTIST, (mArtist != null && mArtist.length() > 0
783997354e4b4a9666cedd62282471e97822affced9Mike Lockwood                            ? mArtist : MediaStore.UNKNOWN_STRING));
784997354e4b4a9666cedd62282471e97822affced9Mike Lockwood                    map.put(Video.Media.ALBUM, (mAlbum != null && mAlbum.length() > 0
785997354e4b4a9666cedd62282471e97822affced9Mike Lockwood                            ? mAlbum : MediaStore.UNKNOWN_STRING));
786997354e4b4a9666cedd62282471e97822affced9Mike Lockwood                    map.put(Video.Media.DURATION, mDuration);
787e313f721ad97ad44666dd066a891acb4ddfa8ab3Marco Nelissen                    if (resolution != null) {
788e313f721ad97ad44666dd066a891acb4ddfa8ab3Marco Nelissen                        map.put(Video.Media.RESOLUTION, resolution);
789e313f721ad97ad44666dd066a891acb4ddfa8ab3Marco Nelissen                    }
790997354e4b4a9666cedd62282471e97822affced9Mike Lockwood                } else if (MediaFile.isImageFileType(mFileType)) {
791997354e4b4a9666cedd62282471e97822affced9Mike Lockwood                    // FIXME - add DESCRIPTION
792997354e4b4a9666cedd62282471e97822affced9Mike Lockwood                } else if (MediaFile.isAudioFileType(mFileType)) {
793997354e4b4a9666cedd62282471e97822affced9Mike Lockwood                    map.put(Audio.Media.ARTIST, (mArtist != null && mArtist.length() > 0) ?
794997354e4b4a9666cedd62282471e97822affced9Mike Lockwood                            mArtist : MediaStore.UNKNOWN_STRING);
795997354e4b4a9666cedd62282471e97822affced9Mike Lockwood                    map.put(Audio.Media.ALBUM_ARTIST, (mAlbumArtist != null &&
796997354e4b4a9666cedd62282471e97822affced9Mike Lockwood                            mAlbumArtist.length() > 0) ? mAlbumArtist : null);
797997354e4b4a9666cedd62282471e97822affced9Mike Lockwood                    map.put(Audio.Media.ALBUM, (mAlbum != null && mAlbum.length() > 0) ?
798997354e4b4a9666cedd62282471e97822affced9Mike Lockwood                            mAlbum : MediaStore.UNKNOWN_STRING);
799997354e4b4a9666cedd62282471e97822affced9Mike Lockwood                    map.put(Audio.Media.COMPOSER, mComposer);
800e5d0495d5206167c597efcd81436a0f881f069f9Mike Lockwood                    map.put(Audio.Media.GENRE, mGenre);
801997354e4b4a9666cedd62282471e97822affced9Mike Lockwood                    if (mYear != 0) {
802997354e4b4a9666cedd62282471e97822affced9Mike Lockwood                        map.put(Audio.Media.YEAR, mYear);
803997354e4b4a9666cedd62282471e97822affced9Mike Lockwood                    }
804997354e4b4a9666cedd62282471e97822affced9Mike Lockwood                    map.put(Audio.Media.TRACK, mTrack);
805997354e4b4a9666cedd62282471e97822affced9Mike Lockwood                    map.put(Audio.Media.DURATION, mDuration);
806997354e4b4a9666cedd62282471e97822affced9Mike Lockwood                    map.put(Audio.Media.COMPILATION, mCompilation);
8079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
8089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return map;
8109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
81120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
81258ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen        private Uri endFile(FileEntry entry, boolean ringtones, boolean notifications,
81320b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync                boolean alarms, boolean music, boolean podcasts)
8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                throws RemoteException {
8159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // update database
81620b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
817997354e4b4a9666cedd62282471e97822affced9Mike Lockwood            // use album artist if artist is missing
8189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mArtist == null || mArtist.length() == 0) {
8199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mArtist = mAlbumArtist;
8209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ContentValues values = toValues();
8239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String title = values.getAsString(MediaStore.MediaColumns.TITLE);
824bdc0e82f9c075edb67da4a2583e557824c280415Mike Lockwood            if (title == null || TextUtils.isEmpty(title.trim())) {
825c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood                title = MediaFile.getFileTitle(values.getAsString(MediaStore.MediaColumns.DATA));
8269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                values.put(MediaStore.MediaColumns.TITLE, title);
8279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
828c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen            String album = values.getAsString(Audio.Media.ALBUM);
8299a488b44cb479bc42375d2cfcdd4aa6161dc17cfMarco Nelissen            if (MediaStore.UNKNOWN_STRING.equals(album)) {
830c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen                album = values.getAsString(MediaStore.MediaColumns.DATA);
831c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen                // extract last path segment before file name
832c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen                int lastSlash = album.lastIndexOf('/');
833c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen                if (lastSlash >= 0) {
834c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen                    int previousSlash = 0;
835c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen                    while (true) {
836c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen                        int idx = album.indexOf('/', previousSlash + 1);
837c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen                        if (idx < 0 || idx >= lastSlash) {
838c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen                            break;
839c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen                        }
840c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen                        previousSlash = idx;
841c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen                    }
842c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen                    if (previousSlash != 0) {
843c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen                        album = album.substring(previousSlash + 1, lastSlash);
844c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen                        values.put(Audio.Media.ALBUM, album);
845c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen                    }
846c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen                }
847c3c08ba5d67d836274fabdf4c1bff6f1053d95a3Marco Nelissen            }
848c066557378c2305625a7bad3d25f084ad647ef27Marco Nelissen            long rowId = entry.mRowId;
849c2206a0710a3ca2c29854c1a0638c5ba55629ba2Mike Lockwood            if (MediaFile.isAudioFileType(mFileType) && (rowId == 0 || mMtpObjectHandle != 0)) {
850c066557378c2305625a7bad3d25f084ad647ef27Marco Nelissen                // Only set these for new entries. For existing entries, they
851c066557378c2305625a7bad3d25f084ad647ef27Marco Nelissen                // may have been modified later, and we want to keep the current
852c066557378c2305625a7bad3d25f084ad647ef27Marco Nelissen                // values so that custom ringtones still show up in the ringtone
853c066557378c2305625a7bad3d25f084ad647ef27Marco Nelissen                // picker.
8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                values.put(Audio.Media.IS_RINGTONE, ringtones);
8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                values.put(Audio.Media.IS_NOTIFICATION, notifications);
8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                values.put(Audio.Media.IS_ALARM, alarms);
8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                values.put(Audio.Media.IS_MUSIC, music);
8589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                values.put(Audio.Media.IS_PODCAST, podcasts);
859997354e4b4a9666cedd62282471e97822affced9Mike Lockwood            } else if (mFileType == MediaFile.FILE_TYPE_JPEG && !mNoMedia) {
860700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang                ExifInterface exif = null;
861700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang                try {
862700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang                    exif = new ExifInterface(entry.mPath);
863700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang                } catch (IOException ex) {
864700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang                    // exif is null
865700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang                }
866700beb484624a9a34649cb6ff088468e78b758ffChih-Chung Chang                if (exif != null) {
867872a30ec723ebdd97de764406544516545d7c9d4Chih-Chung Chang                    float[] latlng = new float[2];
868872a30ec723ebdd97de764406544516545d7c9d4Chih-Chung Chang                    if (exif.getLatLong(latlng)) {
86920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync                        values.put(Images.Media.LATITUDE, latlng[0]);
87020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync                        values.put(Images.Media.LONGITUDE, latlng[1]);
87120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync                    }
872099397cbd07c8c991f3126d0d0ac64bb6b3c0b47Chih-Chung Chang
8733a8cab88e7747dc280ce85895af014f98e80a6ccRay Chen                    long time = exif.getGpsDateTime();
874099397cbd07c8c991f3126d0d0ac64bb6b3c0b47Chih-Chung Chang                    if (time != -1) {
875052d9c8b414dc9eb1c70d849660592d9bc3b2644Ray Chen                        values.put(Images.Media.DATE_TAKEN, time);
876a2c322f599b5a44ca153922b994a05a4311331cbRay Chen                    } else {
877a2c322f599b5a44ca153922b994a05a4311331cbRay Chen                        // If no time zone information is available, we should consider using
878a2c322f599b5a44ca153922b994a05a4311331cbRay Chen                        // EXIF local time as taken time if the difference between file time
879a2c322f599b5a44ca153922b994a05a4311331cbRay Chen                        // and EXIF local time is not less than 1 Day, otherwise MediaProvider
880a2c322f599b5a44ca153922b994a05a4311331cbRay Chen                        // will use file time as taken time.
881a2c322f599b5a44ca153922b994a05a4311331cbRay Chen                        time = exif.getDateTime();
882872e7b7073fad8295e6314c73b87d7cb3f85d39cRay Chen                        if (time != -1 && Math.abs(mLastModified * 1000 - time) >= 86400000) {
883a2c322f599b5a44ca153922b994a05a4311331cbRay Chen                            values.put(Images.Media.DATE_TAKEN, time);
884a2c322f599b5a44ca153922b994a05a4311331cbRay Chen                        }
885099397cbd07c8c991f3126d0d0ac64bb6b3c0b47Chih-Chung Chang                    }
886b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang
887b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang                    int orientation = exif.getAttributeInt(
888b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang                        ExifInterface.TAG_ORIENTATION, -1);
889b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang                    if (orientation != -1) {
890b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang                        // We only recognize a subset of orientation tag values.
891b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang                        int degree;
892b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang                        switch(orientation) {
893b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang                            case ExifInterface.ORIENTATION_ROTATE_90:
894b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang                                degree = 90;
895b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang                                break;
896b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang                            case ExifInterface.ORIENTATION_ROTATE_180:
897b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang                                degree = 180;
898b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang                                break;
899b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang                            case ExifInterface.ORIENTATION_ROTATE_270:
900b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang                                degree = 270;
901b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang                                break;
902b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang                            default:
903b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang                                degree = 0;
904b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang                                break;
905b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang                        }
906b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang                        values.put(Images.Media.ORIENTATION, degree);
907b8f4725d1bb750e3358a5b5dfcec7b1c5d3b9939Chih-Chung Chang                    }
90820b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync                }
9099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
91020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
91145aaa2a345292bb6d600822db602f25e261c0e50Mike Lockwood            Uri tableUri = mFilesUri;
9128e2ed8d512ade2ea481b3a292556782b17a74674Dongwon Kang            MediaInserter inserter = mMediaInserter;
913e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood            if (!mNoMedia) {
914e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood                if (MediaFile.isVideoFileType(mFileType)) {
915e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood                    tableUri = mVideoUri;
916e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood                } else if (MediaFile.isImageFileType(mFileType)) {
917e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood                    tableUri = mImagesUri;
918e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood                } else if (MediaFile.isAudioFileType(mFileType)) {
919e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood                    tableUri = mAudioUri;
920e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood                }
921e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood            }
9229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Uri result = null;
9236c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim            boolean needToSetSettings = false;
9249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (rowId == 0) {
925c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood                if (mMtpObjectHandle != 0) {
926c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood                    values.put(MediaStore.MediaColumns.MEDIA_SCANNER_NEW_OBJECT_ID, mMtpObjectHandle);
927c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood                }
928e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood                if (tableUri == mFilesUri) {
929e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood                    int format = entry.mFormat;
930e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood                    if (format == 0) {
931e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood                        format = MediaFile.getFormatCode(entry.mPath, mMimeType);
932e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood                    }
933e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood                    values.put(Files.FileColumns.FORMAT, format);
934c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood                }
9356c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim                // Setting a flag in order not to use bulk insert for the file related with
9366c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim                // notifications, ringtones, and alarms, because the rowId of the inserted file is
9376c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim                // needed.
9386c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim                if (mWasEmptyPriorToScan) {
9396c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim                    if (notifications && !mDefaultNotificationSet) {
9406c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim                        if (TextUtils.isEmpty(mDefaultNotificationFilename) ||
9416c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim                                doesPathHaveFilename(entry.mPath, mDefaultNotificationFilename)) {
9426c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim                            needToSetSettings = true;
9436c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim                        }
9446c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim                    } else if (ringtones && !mDefaultRingtoneSet) {
9456c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim                        if (TextUtils.isEmpty(mDefaultRingtoneFilename) ||
9466c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim                                doesPathHaveFilename(entry.mPath, mDefaultRingtoneFilename)) {
9476c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim                            needToSetSettings = true;
9486c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim                        }
9496c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim                    } else if (alarms && !mDefaultAlarmSet) {
9506c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim                        if (TextUtils.isEmpty(mDefaultAlarmAlertFilename) ||
9516c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim                                doesPathHaveFilename(entry.mPath, mDefaultAlarmAlertFilename)) {
9526c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim                            needToSetSettings = true;
9536c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim                        }
9546c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim                    }
9556c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim                }
9566c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim
957d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen                // New file, insert it.
958d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen                // Directories need to be inserted before the files they contain, so they
959d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen                // get priority when bulk inserting.
960d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen                // If the rowId of the inserted file is needed, it gets inserted immediately,
961d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen                // bypassing the bulk inserter.
962d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen                if (inserter == null || needToSetSettings) {
963299942002b17f792e6e4f6b3f6972f62b8b136aeMarco Nelissen                    if (inserter != null) {
964299942002b17f792e6e4f6b3f6972f62b8b136aeMarco Nelissen                        inserter.flushAll();
965299942002b17f792e6e4f6b3f6972f62b8b136aeMarco Nelissen                    }
96635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    result = mMediaProvider.insert(mPackageName, tableUri, values);
967d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen                } else if (entry.mFormat == MtpConstants.FORMAT_ASSOCIATION) {
968d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen                    inserter.insertwithPriority(tableUri, values);
969c6eaa713a3f5b9337eca60ba2ab570cf6e80c357Mike Lockwood                } else {
9708e2ed8d512ade2ea481b3a292556782b17a74674Dongwon Kang                    inserter.insert(tableUri, values);
971bd682b040833fce9e212c00c395b32bec7050f87Mike Lockwood                }
972bd682b040833fce9e212c00c395b32bec7050f87Mike Lockwood
9739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (result != null) {
9749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    rowId = ContentUris.parseId(result);
9759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    entry.mRowId = rowId;
9769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
9779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
9789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // updated file
97945aaa2a345292bb6d600822db602f25e261c0e50Mike Lockwood                result = ContentUris.withAppendedId(tableUri, rowId);
9800dd9f4de3ed681e83bd79ddcd4fd463093d11ed3Mike Lockwood                // path should never change, and we want to avoid replacing mixed cased paths
9810dd9f4de3ed681e83bd79ddcd4fd463093d11ed3Mike Lockwood                // with squashed lower case paths
9820dd9f4de3ed681e83bd79ddcd4fd463093d11ed3Mike Lockwood                values.remove(MediaStore.MediaColumns.DATA);
983ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen
984ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen                int mediaType = 0;
985ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen                if (!MediaScanner.isNoMediaPath(entry.mPath)) {
986ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen                    int fileType = MediaFile.getFileTypeForMimeType(mMimeType);
987ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen                    if (MediaFile.isAudioFileType(fileType)) {
988ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen                        mediaType = FileColumns.MEDIA_TYPE_AUDIO;
989ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen                    } else if (MediaFile.isVideoFileType(fileType)) {
990ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen                        mediaType = FileColumns.MEDIA_TYPE_VIDEO;
991ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen                    } else if (MediaFile.isImageFileType(fileType)) {
992ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen                        mediaType = FileColumns.MEDIA_TYPE_IMAGE;
993ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen                    } else if (MediaFile.isPlayListFileType(fileType)) {
994ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen                        mediaType = FileColumns.MEDIA_TYPE_PLAYLIST;
995ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen                    }
996ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen                    values.put(FileColumns.MEDIA_TYPE, mediaType);
997ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen                }
99835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                mMediaProvider.update(mPackageName, result, values, null, null);
9999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
100020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
10016c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim            if(needToSetSettings) {
10026c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim                if (notifications) {
100345aaa2a345292bb6d600822db602f25e261c0e50Mike Lockwood                    setSettingIfNotSet(Settings.System.NOTIFICATION_SOUND, tableUri, rowId);
10049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mDefaultNotificationSet = true;
10056c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim                } else if (ringtones) {
100645aaa2a345292bb6d600822db602f25e261c0e50Mike Lockwood                    setSettingIfNotSet(Settings.System.RINGTONE, tableUri, rowId);
10079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mDefaultRingtoneSet = true;
10086c4c15569674e6a5eda0565b501b600a50d4ca6eSungsoo Lim                } else if (alarms) {
100945aaa2a345292bb6d600822db602f25e261c0e50Mike Lockwood                    setSettingIfNotSet(Settings.System.ALARM_ALERT, tableUri, rowId);
10103156bb00dd3ab3d6ec732bb6a64a2e84d08c34f0Patrick Scott                    mDefaultAlarmSet = true;
10113156bb00dd3ab3d6ec732bb6a64a2e84d08c34f0Patrick Scott                }
10129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
101320b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
10149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return result;
10159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
101620b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
10179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private boolean doesPathHaveFilename(String path, String filename) {
10189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int pathFilenameStart = path.lastIndexOf(File.separatorChar) + 1;
10199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int filenameLength = filename.length();
10209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return path.regionMatches(pathFilenameStart, filename, 0, filenameLength) &&
10219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    pathFilenameStart + filenameLength == path.length();
10229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
102320b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
10249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private void setSettingIfNotSet(String settingName, Uri uri, long rowId) {
102520b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
10269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String existingSettingValue = Settings.System.getString(mContext.getContentResolver(),
10279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    settingName);
102820b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
10299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (TextUtils.isEmpty(existingSettingValue)) {
10309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Set the setting to the given URI
10319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Settings.System.putString(mContext.getContentResolver(), settingName,
10329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        ContentUris.withAppendedId(uri, rowId).toString());
10339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
103520b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
10365d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang        private int getFileTypeFromDrm(String path) {
1037e4eb4d9de37a8e9ed6f43a5f7deccf88f28bfc8bMarco Nelissen            if (!isDrmEnabled()) {
10385d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang                return 0;
10395d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang            }
10405d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang
10415d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang            int resultFileType = 0;
10425d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang
10435d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang            if (mDrmManagerClient == null) {
10445d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang                mDrmManagerClient = new DrmManagerClient(mContext);
10455d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang            }
10465d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang
10475d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang            if (mDrmManagerClient.canHandle(path, null)) {
104859c14048bfc0a210077192410afa28ed6f85daa0Erik Almqvist                mIsDrm = true;
10495d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang                String drmMimetype = mDrmManagerClient.getOriginalMimeType(path);
10505d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang                if (drmMimetype != null) {
10515d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang                    mMimeType = drmMimetype;
10525d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang                    resultFileType = MediaFile.getFileTypeForMimeType(drmMimetype);
10535d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang                }
10545d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang            }
10555d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang            return resultFileType;
10565d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang        }
10575d143ad4a8f8c90f44e185a494ff3ff638e6c103Gloria Wang
10589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }; // end of anonymous MediaScannerClient instance
105920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
1060c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood    private void prescan(String filePath, boolean prescanFiles) throws RemoteException {
10619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Cursor c = null;
10629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String where = null;
10639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String[] selectionArgs = null;
106420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
10659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mPlayLists == null) {
106658ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen            mPlayLists = new ArrayList<FileEntry>();
10679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
10689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mPlayLists.clear();
10699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
107020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
1071c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood        if (filePath != null) {
1072c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood            // query for only one file
107358ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen            where = MediaStore.Files.FileColumns._ID + ">?" +
107458ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                " AND " + Files.FileColumns.DATA + "=?";
107558ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen            selectionArgs = new String[] { "", filePath };
107658ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen        } else {
107758ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen            where = MediaStore.Files.FileColumns._ID + ">?";
107858ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen            selectionArgs = new String[] { "" };
1079c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood        }
1080c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood
108158ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen        // Tell the provider to not delete the file.
108258ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen        // If the file is truly gone the delete is unnecessary, and we want to avoid
108358ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen        // accidentally deleting files that are really there (this may happen if the
108458ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen        // filesystem is mounted and unmounted while the scanner is running).
108558ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen        Uri.Builder builder = mFilesUri.buildUpon();
108658ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen        builder.appendQueryParameter(MediaStore.PARAM_DELETE_DATA, "false");
108735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        MediaBulkDeleter deleter = new MediaBulkDeleter(mMediaProvider, mPackageName,
108835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                builder.build());
108958ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen
10909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Build the list of files from the content provider
10919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
1092c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood            if (prescanFiles) {
109358ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                // First read existing files from the files table.
109458ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                // Because we'll be deleting entries for missing files as we go,
109558ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                // we need to query the database in small batches, to avoid problems
109658ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                // with CursorWindow positioning.
109758ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                long lastId = Long.MIN_VALUE;
109858ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                Uri limitUri = mFilesUri.buildUpon().appendQueryParameter("limit", "1000").build();
109958ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                mWasEmptyPriorToScan = true;
110058ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen
110158ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                while (true) {
110258ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                    selectionArgs[0] = "" + lastId;
110358ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                    if (c != null) {
110458ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                        c.close();
110558ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                        c = null;
110658ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                    }
110735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    c = mMediaProvider.query(mPackageName, limitUri, FILES_PRESCAN_PROJECTION,
110858ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                            where, selectionArgs, MediaStore.Files.FileColumns._ID, null);
110958ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                    if (c == null) {
111058ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                        break;
111158ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                    }
111220b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
111358ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                    int num = c.getCount();
1114c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood
111558ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                    if (num == 0) {
111658ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                        break;
111758ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                    }
111858ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                    mWasEmptyPriorToScan = false;
11199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    while (c.moveToNext()) {
1120d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood                        long rowId = c.getLong(FILES_PRESCAN_ID_COLUMN_INDEX);
1121d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood                        String path = c.getString(FILES_PRESCAN_PATH_COLUMN_INDEX);
1122d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood                        int format = c.getInt(FILES_PRESCAN_FORMAT_COLUMN_INDEX);
1123d7456c650ef4e105f9835236b79244d906e2f1e0Mike Lockwood                        long lastModified = c.getLong(FILES_PRESCAN_DATE_MODIFIED_COLUMN_INDEX);
112458ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                        lastId = rowId;
112520b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
112635b002a9c873fb40116179c8626b9841b0abae74Marco Nelissen                        // Only consider entries with absolute path names.
112735b002a9c873fb40116179c8626b9841b0abae74Marco Nelissen                        // This allows storing URIs in the database without the
112835b002a9c873fb40116179c8626b9841b0abae74Marco Nelissen                        // media scanner removing them.
11293e5e8055942ee8179675b8ed11d40ca12dbe42e6Marco Nelissen                        if (path != null && path.startsWith("/")) {
113058ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                            boolean exists = false;
113158ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                            try {
113234385d352da19805ae948215e2edbeedd16b7941Elliott Hughes                                exists = Os.access(path, android.system.OsConstants.F_OK);
113358ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                            } catch (ErrnoException e1) {
113458ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                            }
113558ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                            if (!exists && !MtpConstants.isAbstractObject(format)) {
113658ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                                // do not delete missing playlists, since they may have been
113758ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                                // modified by the user.
113858ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                                // The user can delete them in the media player instead.
113958ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                                // instead, clear the path and lastModified fields in the row
114058ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                                MediaFile.MediaFileType mediaFileType = MediaFile.getFileType(path);
114158ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                                int fileType = (mediaFileType == null ? 0 : mediaFileType.fileType);
114258ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen
114358ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                                if (!MediaFile.isPlayListFileType(fileType)) {
114458ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                                    deleter.delete(rowId);
114558ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                                    if (path.toLowerCase(Locale.US).endsWith("/.nomedia")) {
114658ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                                        deleter.flush();
114758ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                                        String parent = new File(path).getParent();
114835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                                        mMediaProvider.call(mPackageName, MediaStore.UNHIDE_CALL,
114935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                                                parent, null);
115058ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                                    }
115158ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                                }
115235b002a9c873fb40116179c8626b9841b0abae74Marco Nelissen                            }
11539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
11549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
11559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
11569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        finally {
11599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (c != null) {
11609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                c.close();
11619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
116258ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen            deleter.flush();
11639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11646458935331ccfacb4cccc50d6b893947febae687Mike Lockwood
11656458935331ccfacb4cccc50d6b893947febae687Mike Lockwood        // compute original size of images
11666458935331ccfacb4cccc50d6b893947febae687Mike Lockwood        mOriginalCount = 0;
116735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        c = mMediaProvider.query(mPackageName, mImagesUri, ID_PROJECTION, null, null, null, null);
11686458935331ccfacb4cccc50d6b893947febae687Mike Lockwood        if (c != null) {
11696458935331ccfacb4cccc50d6b893947febae687Mike Lockwood            mOriginalCount = c.getCount();
11706458935331ccfacb4cccc50d6b893947febae687Mike Lockwood            c.close();
11716458935331ccfacb4cccc50d6b893947febae687Mike Lockwood        }
11729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
117320b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
11749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean inScanDirectory(String path, String[] directories) {
11759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < directories.length; i++) {
1176f45853af5051df4abaa33cdca7fa986104811d1aMike Lockwood            String directory = directories[i];
1177f45853af5051df4abaa33cdca7fa986104811d1aMike Lockwood            if (path.startsWith(directory)) {
11789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
11799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
11829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
118320b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
11849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void pruneDeadThumbnailFiles() {
11859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        HashSet<String> existingFiles = new HashSet<String>();
11869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String directory = "/sdcard/DCIM/.thumbnails";
11879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String [] files = (new File(directory)).list();
1188f3fd18d1b4cb44bb31a5b4fba26136f6f4fc37adMattias Nilsson        Cursor c = null;
11899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (files == null)
11909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            files = new String[0];
119120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
11929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < files.length; i++) {
11939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String fullPathString = directory + "/" + files[i];
11949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            existingFiles.add(fullPathString);
11959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
119620b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
11979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
1198f3fd18d1b4cb44bb31a5b4fba26136f6f4fc37adMattias Nilsson            c = mMediaProvider.query(
119935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    mPackageName,
120020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync                    mThumbsUri,
120120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync                    new String [] { "_data" },
120220b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync                    null,
120320b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync                    null,
120475ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown                    null, null);
12059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.v(TAG, "pruneDeadThumbnailFiles... " + c);
12069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (c != null && c.moveToFirst()) {
12079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                do {
12089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    String fullPathString = c.getString(0);
12099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    existingFiles.remove(fullPathString);
12109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } while (c.moveToNext());
12119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
121220b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
12139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (String fileToDelete : existingFiles) {
121443a17654cf4bfe7f1ec22bd8b7b32daccdf27c09Joe Onorato                if (false)
12159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Log.v(TAG, "fileToDelete is " + fileToDelete);
12169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
12179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    (new File(fileToDelete)).delete();
12189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (SecurityException ex) {
12199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
12209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
122120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
12229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.v(TAG, "/pruneDeadThumbnailFiles... " + c);
1223f3fd18d1b4cb44bb31a5b4fba26136f6f4fc37adMattias Nilsson        } catch (RemoteException e) {
1224f3fd18d1b4cb44bb31a5b4fba26136f6f4fc37adMattias Nilsson            // We will soon be killed...
1225f3fd18d1b4cb44bb31a5b4fba26136f6f4fc37adMattias Nilsson        } finally {
12269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (c != null) {
12279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                c.close();
12289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
12299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12329ff4774cac499a376a59373d5bfb5112c9a2a004Marco Nelissen    static class MediaBulkDeleter {
1233d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen        StringBuilder whereClause = new StringBuilder();
1234872e7b7073fad8295e6314c73b87d7cb3f85d39cRay Chen        ArrayList<String> whereArgs = new ArrayList<String>(100);
123535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        final IContentProvider mProvider;
123635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        final String mPackageName;
123735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        final Uri mBaseUri;
12389ff4774cac499a376a59373d5bfb5112c9a2a004Marco Nelissen
123935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        public MediaBulkDeleter(IContentProvider provider, String packageName, Uri baseUri) {
12409ff4774cac499a376a59373d5bfb5112c9a2a004Marco Nelissen            mProvider = provider;
124135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            mPackageName = packageName;
12429ff4774cac499a376a59373d5bfb5112c9a2a004Marco Nelissen            mBaseUri = baseUri;
12439ff4774cac499a376a59373d5bfb5112c9a2a004Marco Nelissen        }
12449ff4774cac499a376a59373d5bfb5112c9a2a004Marco Nelissen
12459ff4774cac499a376a59373d5bfb5112c9a2a004Marco Nelissen        public void delete(long id) throws RemoteException {
1246d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen            if (whereClause.length() != 0) {
1247d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen                whereClause.append(",");
12489ff4774cac499a376a59373d5bfb5112c9a2a004Marco Nelissen            }
1249d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen            whereClause.append("?");
1250d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen            whereArgs.add("" + id);
1251d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen            if (whereArgs.size() > 100) {
12529ff4774cac499a376a59373d5bfb5112c9a2a004Marco Nelissen                flush();
12539ff4774cac499a376a59373d5bfb5112c9a2a004Marco Nelissen            }
12549ff4774cac499a376a59373d5bfb5112c9a2a004Marco Nelissen        }
12559ff4774cac499a376a59373d5bfb5112c9a2a004Marco Nelissen        public void flush() throws RemoteException {
1256d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen            int size = whereArgs.size();
1257d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen            if (size > 0) {
1258d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen                String [] foo = new String [size];
1259d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen                foo = whereArgs.toArray(foo);
126035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                int numrows = mProvider.delete(mPackageName, mBaseUri,
126135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        MediaStore.MediaColumns._ID + " IN (" +
1262d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen                        whereClause.toString() + ")", foo);
1263d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen                //Log.i("@@@@@@@@@", "rows deleted: " + numrows);
1264d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen                whereClause.setLength(0);
1265d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen                whereArgs.clear();
1266d121cfcbb45cb9ca734e702861f0bdd422999cf5Marco Nelissen            }
12679ff4774cac499a376a59373d5bfb5112c9a2a004Marco Nelissen        }
12689ff4774cac499a376a59373d5bfb5112c9a2a004Marco Nelissen    }
12699ff4774cac499a376a59373d5bfb5112c9a2a004Marco Nelissen
12709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void postscan(String[] directories) throws RemoteException {
127120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
12729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // handle playlists last, after we know what media files are on the storage.
12739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mProcessPlaylists) {
12749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            processPlayLists();
12759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
127620b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
12779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mOriginalCount == 0 && mImagesUri.equals(Images.Media.getContentUri("external")))
12789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pruneDeadThumbnailFiles();
127920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
12809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // allow GC to clean up
12819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mPlayLists = null;
12829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mMediaProvider = null;
12839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
128420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
12851b37c3bddcdfe7cb60e776e3eb05bfbb46b0b282Mattias Nilsson    private void releaseResources() {
12861b37c3bddcdfe7cb60e776e3eb05bfbb46b0b282Mattias Nilsson        // release the DrmManagerClient resources
12871b37c3bddcdfe7cb60e776e3eb05bfbb46b0b282Mattias Nilsson        if (mDrmManagerClient != null) {
12881b37c3bddcdfe7cb60e776e3eb05bfbb46b0b282Mattias Nilsson            mDrmManagerClient.release();
12891b37c3bddcdfe7cb60e776e3eb05bfbb46b0b282Mattias Nilsson            mDrmManagerClient = null;
12901b37c3bddcdfe7cb60e776e3eb05bfbb46b0b282Mattias Nilsson        }
12911b37c3bddcdfe7cb60e776e3eb05bfbb46b0b282Mattias Nilsson    }
12921b37c3bddcdfe7cb60e776e3eb05bfbb46b0b282Mattias Nilsson
12939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void initialize(String volumeName) {
12949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mMediaProvider = mContext.getContentResolver().acquireProvider("media");
129520b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
12969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mAudioUri = Audio.Media.getContentUri(volumeName);
12979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mVideoUri = Video.Media.getContentUri(volumeName);
12989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mImagesUri = Images.Media.getContentUri(volumeName);
12999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mThumbsUri = Images.Thumbnails.getContentUri(volumeName);
1300c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood        mFilesUri = Files.getContentUri(volumeName);
13018ad76fa7a644c10abb7b95398fdb8a84bd723619Marco Nelissen        mFilesUriNoNotify = mFilesUri.buildUpon().appendQueryParameter("nonotify", "1").build();
13029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!volumeName.equals("internal")) {
13049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // we only support playlists on external media
13059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mProcessPlaylists = true;
130643b076bb75e86fbb34cbe36aa0298c7a647121ffMike Lockwood            mProcessGenres = true;
13079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mPlaylistsUri = Playlists.getContentUri(volumeName);
1308f73738b78a8396552274cf33b0021f414fb7201dMike Lockwood
1309f50e54e64b2b5a269e1a88c511a57064a14bb51bDianne Hackborn            mCaseInsensitivePaths = true;
131020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync        }
13119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void scanDirectories(String[] directories, String volumeName) {
13149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
13159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            long start = System.currentTimeMillis();
131620b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync            initialize(volumeName);
1317c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood            prescan(null, true);
13189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            long prescan = System.currentTimeMillis();
1319e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood
13203410b4656505673c72da558dcfec94d7b135e760Mike Lockwood            if (ENABLE_BULK_INSERTS) {
13218e2ed8d512ade2ea481b3a292556782b17a74674Dongwon Kang                // create MediaInserter for bulk inserts
132235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                mMediaInserter = new MediaInserter(mMediaProvider, mPackageName, 500);
13233410b4656505673c72da558dcfec94d7b135e760Mike Lockwood            }
132420b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
13259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < directories.length; i++) {
1326c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood                processDirectory(directories[i], mClient);
13279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1328e19572ccb5e7963eee9dd1cca150ee752a850e4aMike Lockwood
13293410b4656505673c72da558dcfec94d7b135e760Mike Lockwood            if (ENABLE_BULK_INSERTS) {
13303410b4656505673c72da558dcfec94d7b135e760Mike Lockwood                // flush remaining inserts
13318e2ed8d512ade2ea481b3a292556782b17a74674Dongwon Kang                mMediaInserter.flushAll();
13328e2ed8d512ade2ea481b3a292556782b17a74674Dongwon Kang                mMediaInserter = null;
13333410b4656505673c72da558dcfec94d7b135e760Mike Lockwood            }
1334bd682b040833fce9e212c00c395b32bec7050f87Mike Lockwood
13359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            long scan = System.currentTimeMillis();
13369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            postscan(directories);
13379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            long end = System.currentTimeMillis();
133820b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
133943a17654cf4bfe7f1ec22bd8b7b32daccdf27c09Joe Onorato            if (false) {
13409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Log.d(TAG, " prescan time: " + (prescan - start) + "ms\n");
13419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Log.d(TAG, "    scan time: " + (scan - prescan) + "ms\n");
13429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Log.d(TAG, "postscan time: " + (end - scan) + "ms\n");
13439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Log.d(TAG, "   total time: " + (end - start) + "ms\n");
13449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
13459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (SQLException e) {
13469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // this might happen if the SD card is removed while the media scanner is running
13479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.e(TAG, "SQLException in MediaScanner.scan()", e);
13489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (UnsupportedOperationException e) {
13499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // this might happen if the SD card is removed while the media scanner is running
13509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.e(TAG, "UnsupportedOperationException in MediaScanner.scan()", e);
13519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (RemoteException e) {
13529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.e(TAG, "RemoteException in MediaScanner.scan()", e);
13531b37c3bddcdfe7cb60e776e3eb05bfbb46b0b282Mattias Nilsson        } finally {
13541b37c3bddcdfe7cb60e776e3eb05bfbb46b0b282Mattias Nilsson            releaseResources();
13559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // this function is used to scan a single file
13599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Uri scanSingleFile(String path, String volumeName, String mimeType) {
13609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
136120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync            initialize(volumeName);
1362c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood            prescan(path, true);
136320b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
13649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            File file = new File(path);
1365348aa65e93c1b8cb409de12e3e61136f894201f2Marco Nelissen            if (!file.exists()) {
1366348aa65e93c1b8cb409de12e3e61136f894201f2Marco Nelissen                return null;
1367348aa65e93c1b8cb409de12e3e61136f894201f2Marco Nelissen            }
1368ec74abb71f79cdc573c536115acc7ff26a02680aMikael
1369ec74abb71f79cdc573c536115acc7ff26a02680aMikael            // lastModified is in milliseconds on Files.
1370ec74abb71f79cdc573c536115acc7ff26a02680aMikael            long lastModifiedSeconds = file.lastModified() / 1000;
1371ec74abb71f79cdc573c536115acc7ff26a02680aMikael
13729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // always scan the file, so we can return the content://media Uri for existing files
13737a0bd17bceaf3efc3732e30c538fae420d3b742cMike Lockwood            return mClient.doScanFile(path, mimeType, lastModifiedSeconds, file.length(),
137466dfcd465c02d78cb4ff22e7b509ee42d4309286Marco Nelissen                    false, true, MediaScanner.isNoMediaPath(path));
13759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (RemoteException e) {
13769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.e(TAG, "RemoteException in MediaScanner.scanFile()", e);
13779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return null;
13781b37c3bddcdfe7cb60e776e3eb05bfbb46b0b282Mattias Nilsson        } finally {
13791b37c3bddcdfe7cb60e776e3eb05bfbb46b0b282Mattias Nilsson            releaseResources();
13809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1383ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood    private static boolean isNoMediaFile(String path) {
1384ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood        File file = new File(path);
1385ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood        if (file.isDirectory()) return false;
1386ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood
1387ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood        // special case certain file names
1388ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood        // I use regionMatches() instead of substring() below
1389ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood        // to avoid memory allocation
1390ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood        int lastSlash = path.lastIndexOf('/');
1391ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood        if (lastSlash >= 0 && lastSlash + 2 < path.length()) {
1392ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood            // ignore those ._* files created by MacOS
1393ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood            if (path.regionMatches(lastSlash + 1, "._", 0, 2)) {
1394ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood                return true;
1395ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood            }
1396ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood
1397ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood            // ignore album art files created by Windows Media Player:
1398ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood            // Folder.jpg, AlbumArtSmall.jpg, AlbumArt_{...}_Large.jpg
1399ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood            // and AlbumArt_{...}_Small.jpg
1400ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood            if (path.regionMatches(true, path.length() - 4, ".jpg", 0, 4)) {
1401ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood                if (path.regionMatches(true, lastSlash + 1, "AlbumArt_{", 0, 10) ||
1402ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood                        path.regionMatches(true, lastSlash + 1, "AlbumArt.", 0, 9)) {
1403ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood                    return true;
1404ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood                }
1405ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood                int length = path.length() - lastSlash - 1;
1406ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood                if ((length == 17 && path.regionMatches(
1407ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood                        true, lastSlash + 1, "AlbumArtSmall", 0, 13)) ||
1408ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood                        (length == 10
1409ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood                         && path.regionMatches(true, lastSlash + 1, "Folder", 0, 6))) {
1410ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood                    return true;
1411ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood                }
1412ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood            }
1413ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood        }
1414ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood        return false;
1415ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood    }
1416ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood
141793a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen    private static HashMap<String,String> mNoMediaPaths = new HashMap<String,String>();
141893a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen    private static HashMap<String,String> mMediaPaths = new HashMap<String,String>();
1419997354e4b4a9666cedd62282471e97822affced9Mike Lockwood
142093a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen    /* MediaProvider calls this when a .nomedia file is added or removed */
142193a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen    public static void clearMediaPathCache(boolean clearMediaPaths, boolean clearNoMediaPaths) {
142293a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen        synchronized (MediaScanner.class) {
142393a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen            if (clearMediaPaths) {
142493a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen                mMediaPaths.clear();
142593a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen            }
142693a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen            if (clearNoMediaPaths) {
142793a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen                mNoMediaPaths.clear();
142893a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen            }
142993a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen        }
143093a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen    }
143193a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen
143293a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen    public static boolean isNoMediaPath(String path) {
143393a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen        if (path == null) {
143493a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen            return false;
143593a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen        }
1436997354e4b4a9666cedd62282471e97822affced9Mike Lockwood        // return true if file or any parent directory has name starting with a dot
143793a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen        if (path.indexOf("/.") >= 0) {
143893a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen            return true;
143993a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen        }
144093a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen
144193a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen        int firstSlash = path.lastIndexOf('/');
1442d5a579765e06d69c1a33663c202c3593a5bd5c6bMarco Nelissen        if (firstSlash <= 0) {
144393a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen            return false;
144493a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen        }
144593a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen        String parent = path.substring(0,  firstSlash);
144693a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen
144793a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen        synchronized (MediaScanner.class) {
144893a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen            if (mNoMediaPaths.containsKey(parent)) {
144993a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen                return true;
145093a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen            } else if (!mMediaPaths.containsKey(parent)) {
145193a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen                // check to see if any parent directories have a ".nomedia" file
145293a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen                // start from 1 so we don't bother checking in the root directory
145393a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen                int offset = 1;
145493a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen                while (offset >= 0) {
145593a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen                    int slashIndex = path.indexOf('/', offset);
145693a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen                    if (slashIndex > offset) {
145793a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen                        slashIndex++; // move past slash
145893a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen                        File file = new File(path.substring(0, slashIndex) + ".nomedia");
145993a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen                        if (file.exists()) {
146093a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen                            // we have a .nomedia in one of the parent directories
146193a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen                            mNoMediaPaths.put(parent, "");
146293a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen                            return true;
146393a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen                        }
146493a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen                    }
146593a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen                    offset = slashIndex;
1466997354e4b4a9666cedd62282471e97822affced9Mike Lockwood                }
146793a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen                mMediaPaths.put(parent, "");
1468997354e4b4a9666cedd62282471e97822affced9Mike Lockwood            }
1469997354e4b4a9666cedd62282471e97822affced9Mike Lockwood        }
147093a5845d1a56dde3be4f0bdae70044724548b7d1Marco Nelissen
1471ade06df0fe3499d66ee5cc29071d41445d1091faMike Lockwood        return isNoMediaFile(path);
1472997354e4b4a9666cedd62282471e97822affced9Mike Lockwood    }
1473997354e4b4a9666cedd62282471e97822affced9Mike Lockwood
1474c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood    public void scanMtpFile(String path, String volumeName, int objectHandle, int format) {
14757a0bd17bceaf3efc3732e30c538fae420d3b742cMike Lockwood        initialize(volumeName);
1476c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood        MediaFile.MediaFileType mediaFileType = MediaFile.getFileType(path);
1477c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood        int fileType = (mediaFileType == null ? 0 : mediaFileType.fileType);
14787a0bd17bceaf3efc3732e30c538fae420d3b742cMike Lockwood        File file = new File(path);
14797a0bd17bceaf3efc3732e30c538fae420d3b742cMike Lockwood        long lastModifiedSeconds = file.lastModified() / 1000;
1480c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood
1481c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood        if (!MediaFile.isAudioFileType(fileType) && !MediaFile.isVideoFileType(fileType) &&
148220c38ea9fd4024cc076c825f46cdfb34ffc090deJan Bjernler            !MediaFile.isImageFileType(fileType) && !MediaFile.isPlayListFileType(fileType) &&
148320c38ea9fd4024cc076c825f46cdfb34ffc090deJan Bjernler            !MediaFile.isDrmFileType(fileType)) {
14847a0bd17bceaf3efc3732e30c538fae420d3b742cMike Lockwood
14857a0bd17bceaf3efc3732e30c538fae420d3b742cMike Lockwood            // no need to use the media scanner, but we need to update last modified and file size
14867a0bd17bceaf3efc3732e30c538fae420d3b742cMike Lockwood            ContentValues values = new ContentValues();
14877a0bd17bceaf3efc3732e30c538fae420d3b742cMike Lockwood            values.put(Files.FileColumns.SIZE, file.length());
14887a0bd17bceaf3efc3732e30c538fae420d3b742cMike Lockwood            values.put(Files.FileColumns.DATE_MODIFIED, lastModifiedSeconds);
14897a0bd17bceaf3efc3732e30c538fae420d3b742cMike Lockwood            try {
14907a0bd17bceaf3efc3732e30c538fae420d3b742cMike Lockwood                String[] whereArgs = new String[] {  Integer.toString(objectHandle) };
149135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                mMediaProvider.update(mPackageName, Files.getMtpObjectsUri(volumeName), values,
149235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        "_id=?", whereArgs);
14937a0bd17bceaf3efc3732e30c538fae420d3b742cMike Lockwood            } catch (RemoteException e) {
14947a0bd17bceaf3efc3732e30c538fae420d3b742cMike Lockwood                Log.e(TAG, "RemoteException in scanMtpFile", e);
14957a0bd17bceaf3efc3732e30c538fae420d3b742cMike Lockwood            }
1496c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood            return;
1497c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood        }
1498c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood
1499d815f79766984fce499e147ecbacc01914683f74Mike Lockwood        mMtpObjectHandle = objectHandle;
1500c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen        Cursor fileList = null;
1501c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood        try {
1502caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood            if (MediaFile.isPlayListFileType(fileType)) {
1503caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood                // build file cache so we can look up tracks in the playlist
1504caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood                prescan(null, true);
1505caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood
150658ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                FileEntry entry = makeEntryFor(path);
1507caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood                if (entry != null) {
150835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    fileList = mMediaProvider.query(mPackageName, mFilesUri,
150935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                            FILES_PRESCAN_PROJECTION, null, null, null, null);
1510c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen                    processPlayList(entry, fileList);
1511caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood                }
1512caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood            } else {
1513caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood                // MTP will create a file entry for us so we don't want to do it in prescan
1514caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood                prescan(path, false);
1515c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood
1516caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood                // always scan the file, so we can return the content://media Uri for existing files
1517076e05b488e40fdd946f0d35137fe66a576efe09Mike Lockwood                mClient.doScanFile(path, mediaFileType.mimeType, lastModifiedSeconds, file.length(),
1518997354e4b4a9666cedd62282471e97822affced9Mike Lockwood                    (format == MtpConstants.FORMAT_ASSOCIATION), true, isNoMediaPath(path));
1519caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood            }
1520c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood        } catch (RemoteException e) {
1521c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood            Log.e(TAG, "RemoteException in MediaScanner.scanFile()", e);
1522c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood        } finally {
1523c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood            mMtpObjectHandle = 0;
1524c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen            if (fileList != null) {
1525c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen                fileList.close();
1526c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen            }
15271b37c3bddcdfe7cb60e776e3eb05bfbb46b0b282Mattias Nilsson            releaseResources();
1528c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood        }
1529d815f79766984fce499e147ecbacc01914683f74Mike Lockwood    }
1530d815f79766984fce499e147ecbacc01914683f74Mike Lockwood
153158ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen    FileEntry makeEntryFor(String path) {
153258ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen        String where;
153358ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen        String[] selectionArgs;
153458ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen
153558ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen        Cursor c = null;
153658ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen        try {
1537da8fe0faf5b52ef65bd07b6f47479ac537d42d47Marco Nelissen            where = Files.FileColumns.DATA + "=?";
1538da8fe0faf5b52ef65bd07b6f47479ac537d42d47Marco Nelissen            selectionArgs = new String[] { path };
153935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            c = mMediaProvider.query(mPackageName, mFilesUriNoNotify, FILES_PRESCAN_PROJECTION,
154058ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                    where, selectionArgs, null, null);
15418ab2dc2f9680307febe997631c2148729f714e3dMarco Nelissen            if (c.moveToFirst()) {
154258ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                long rowId = c.getLong(FILES_PRESCAN_ID_COLUMN_INDEX);
154358ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                int format = c.getInt(FILES_PRESCAN_FORMAT_COLUMN_INDEX);
154458ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                long lastModified = c.getLong(FILES_PRESCAN_DATE_MODIFIED_COLUMN_INDEX);
154558ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                return new FileEntry(rowId, path, lastModified, format);
154658ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen            }
154758ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen        } catch (RemoteException e) {
154858ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen        } finally {
154958ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen            if (c != null) {
155058ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen                c.close();
155158ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen            }
155258ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen        }
155358ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen        return null;
155458ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen    }
155558ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen
15569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // returns the number of matching file/directory names, starting from the right
15579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int matchPaths(String path1, String path2) {
15589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int result = 0;
15599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int end1 = path1.length();
15609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int end2 = path2.length();
156120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
15629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        while (end1 > 0 && end2 > 0) {
15639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int slash1 = path1.lastIndexOf('/', end1 - 1);
15649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int slash2 = path2.lastIndexOf('/', end2 - 1);
15659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int backSlash1 = path1.lastIndexOf('\\', end1 - 1);
15669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int backSlash2 = path2.lastIndexOf('\\', end2 - 1);
15679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int start1 = (slash1 > backSlash1 ? slash1 : backSlash1);
15689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int start2 = (slash2 > backSlash2 ? slash2 : backSlash2);
15699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (start1 < 0) start1 = 0; else start1++;
15709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (start2 < 0) start2 = 0; else start2++;
15719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int length = end1 - start1;
15729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (end2 - start2 != length) break;
15739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (path1.regionMatches(true, start1, path2, start2, length)) {
15749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                result++;
15759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                end1 = start1 - 1;
15769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                end2 = start2 - 1;
15779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else break;
15789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
157920b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
15809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return result;
15819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
15829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15830b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen    private boolean matchEntries(long rowId, String data) {
15840b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen
15850b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen        int len = mPlaylistEntries.size();
15860b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen        boolean done = true;
15870b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen        for (int i = 0; i < len; i++) {
15880b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen            PlaylistEntry entry = mPlaylistEntries.get(i);
15890b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen            if (entry.bestmatchlevel == Integer.MAX_VALUE) {
15900b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen                continue; // this entry has been matched already
15910b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen            }
15920b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen            done = false;
15930b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen            if (data.equalsIgnoreCase(entry.path)) {
15940b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen                entry.bestmatchid = rowId;
15950b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen                entry.bestmatchlevel = Integer.MAX_VALUE;
15960b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen                continue; // no need for path matching
15970b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen            }
15980b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen
15990b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen            int matchLength = matchPaths(data, entry.path);
16000b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen            if (matchLength > entry.bestmatchlevel) {
16010b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen                entry.bestmatchid = rowId;
16020b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen                entry.bestmatchlevel = matchLength;
16030b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen            }
16040b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen        }
16050b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen        return done;
16060b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen    }
160720b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
16080b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen    private void cachePlaylistEntry(String line, String playListDirectory) {
16090b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen        PlaylistEntry entry = new PlaylistEntry();
16109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // watch for trailing whitespace
16110b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen        int entryLength = line.length();
16120b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen        while (entryLength > 0 && Character.isWhitespace(line.charAt(entryLength - 1))) entryLength--;
16139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // path should be longer than 3 characters.
16149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // avoid index out of bounds errors below by returning here.
16150b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen        if (entryLength < 3) return;
16160b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen        if (entryLength < line.length()) line = line.substring(0, entryLength);
16179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // does entry appear to be an absolute path?
16199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // look for Unix or DOS absolute paths
16200b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen        char ch1 = line.charAt(0);
16219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean fullPath = (ch1 == '/' ||
16220b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen                (Character.isLetter(ch1) && line.charAt(1) == ':' && line.charAt(2) == '\\'));
16239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // if we have a relative path, combine entry with playListDirectory
16249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!fullPath)
16250b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen            line = playListDirectory + line;
16260b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen        entry.path = line;
16279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        //FIXME - should we look for "../" within the path?
162820b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
16290b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen        mPlaylistEntries.add(entry);
16300b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen    }
163120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
16320b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen    private void processCachedPlaylist(Cursor fileList, ContentValues values, Uri playlistUri) {
16330b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen        fileList.moveToPosition(-1);
16340b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen        while (fileList.moveToNext()) {
16350b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen            long rowId = fileList.getLong(FILES_PRESCAN_ID_COLUMN_INDEX);
16360b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen            String data = fileList.getString(FILES_PRESCAN_PATH_COLUMN_INDEX);
16370b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen            if (matchEntries(rowId, data)) {
16380b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen                break;
16399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
16409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
164120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
16420b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen        int len = mPlaylistEntries.size();
16430b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen        int index = 0;
16440b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen        for (int i = 0; i < len; i++) {
16450b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen            PlaylistEntry entry = mPlaylistEntries.get(i);
16460b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen            if (entry.bestmatchlevel > 0) {
16470b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen                try {
16480b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen                    values.clear();
16490b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen                    values.put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, Integer.valueOf(index));
16500b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen                    values.put(MediaStore.Audio.Playlists.Members.AUDIO_ID, Long.valueOf(entry.bestmatchid));
165135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    mMediaProvider.insert(mPackageName, playlistUri, values);
16520b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen                    index++;
16530b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen                } catch (RemoteException e) {
16540b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen                    Log.e(TAG, "RemoteException in MediaScanner.processCachedPlaylist()", e);
16550b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen                    return;
16567d92a22d9dec42a45cd55fd77d0a86b4b9c6e9dfDongwon Kang                }
16577d92a22d9dec42a45cd55fd77d0a86b4b9c6e9dfDongwon Kang            }
16589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
16590b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen        mPlaylistEntries.clear();
16609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
166120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
1662c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen    private void processM3uPlayList(String path, String playListDirectory, Uri uri,
1663c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen            ContentValues values, Cursor fileList) {
16649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        BufferedReader reader = null;
16659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
16669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            File f = new File(path);
16679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (f.exists()) {
16689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                reader = new BufferedReader(
16699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        new InputStreamReader(new FileInputStream(f)), 8192);
16709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                String line = reader.readLine();
16710b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen                mPlaylistEntries.clear();
16729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                while (line != null) {
16739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // ignore comment lines, which begin with '#'
16749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (line.length() > 0 && line.charAt(0) != '#') {
16750b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen                        cachePlaylistEntry(line, playListDirectory);
16769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
16779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    line = reader.readLine();
16789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
16790b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen
16800b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen                processCachedPlaylist(fileList, values, uri);
16819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
16829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (IOException e) {
16839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.e(TAG, "IOException in MediaScanner.processM3uPlayList()", e);
16849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
16859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
16869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (reader != null)
16879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    reader.close();
16889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (IOException e) {
16899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Log.e(TAG, "IOException in MediaScanner.processM3uPlayList()", e);
16909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
16919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
16929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
16939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1694c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen    private void processPlsPlayList(String path, String playListDirectory, Uri uri,
1695c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen            ContentValues values, Cursor fileList) {
16969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        BufferedReader reader = null;
16979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
16989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            File f = new File(path);
16999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (f.exists()) {
17009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                reader = new BufferedReader(
17019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        new InputStreamReader(new FileInputStream(f)), 8192);
17029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                String line = reader.readLine();
17030b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen                mPlaylistEntries.clear();
17049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                while (line != null) {
17059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // ignore comment lines, which begin with '#'
17069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (line.startsWith("File")) {
17079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        int equals = line.indexOf('=');
17089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (equals > 0) {
1709538d4925b36067dc89ad0625a69dafeaa364bd2eMarco Nelissen                            cachePlaylistEntry(line.substring(equals + 1), playListDirectory);
17109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
17119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
17129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    line = reader.readLine();
17139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
17140b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen
17150b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen                processCachedPlaylist(fileList, values, uri);
17169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
17179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (IOException e) {
17189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.e(TAG, "IOException in MediaScanner.processPlsPlayList()", e);
17199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
17209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
17219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (reader != null)
17229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    reader.close();
17239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (IOException e) {
17249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Log.e(TAG, "IOException in MediaScanner.processPlsPlayList()", e);
17259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
17269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
17279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
17289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    class WplHandler implements ElementListener {
17309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final ContentHandler handler;
17329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String playListDirectory;
17339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1734c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen        public WplHandler(String playListDirectory, Uri uri, Cursor fileList) {
17359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            this.playListDirectory = playListDirectory;
173620b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
17379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            RootElement root = new RootElement("smil");
17389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Element body = root.getChild("body");
17399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Element seq = body.getChild("seq");
17409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Element media = seq.getChild("media");
17419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            media.setElementListener(this);
17429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            this.handler = root.getContentHandler();
17449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
17459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1746c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen        @Override
17479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void start(Attributes attributes) {
17489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String path = attributes.getValue("", "src");
17499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (path != null) {
17500b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen                cachePlaylistEntry(path, playListDirectory);
17519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
17529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
17539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17540b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen       @Override
17559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project       public void end() {
17569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project       }
17579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ContentHandler getContentHandler() {
17599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return handler;
17609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
17619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
17629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1763c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen    private void processWplPlayList(String path, String playListDirectory, Uri uri,
17640b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen            ContentValues values, Cursor fileList) {
17659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        FileInputStream fis = null;
17669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
17679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            File f = new File(path);
17689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (f.exists()) {
17699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                fis = new FileInputStream(f);
17709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17710b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen                mPlaylistEntries.clear();
1772c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen                Xml.parse(fis, Xml.findEncodingByName("UTF-8"),
1773c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen                        new WplHandler(playListDirectory, uri, fileList).getContentHandler());
17740b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen
17750b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen                processCachedPlaylist(fileList, values, uri);
17769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
17779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (SAXException e) {
17789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            e.printStackTrace();
17799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (IOException e) {
17809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            e.printStackTrace();
17819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
17829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
17839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (fis != null)
17849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    fis.close();
17859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (IOException e) {
17869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Log.e(TAG, "IOException in MediaScanner.processWplPlayList()", e);
17879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
17889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
17899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
179020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
1791c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen    private void processPlayList(FileEntry entry, Cursor fileList) throws RemoteException {
1792caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood        String path = entry.mPath;
1793caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood        ContentValues values = new ContentValues();
1794caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood        int lastSlash = path.lastIndexOf('/');
1795caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood        if (lastSlash < 0) throw new IllegalArgumentException("bad path " + path);
1796caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood        Uri uri, membersUri;
1797caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood        long rowId = entry.mRowId;
1798caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood
1799242d0cdc1ad6c48faca403ea352bde73138443b5Mike Lockwood        // make sure we have a name
1800242d0cdc1ad6c48faca403ea352bde73138443b5Mike Lockwood        String name = values.getAsString(MediaStore.Audio.Playlists.NAME);
1801242d0cdc1ad6c48faca403ea352bde73138443b5Mike Lockwood        if (name == null) {
1802242d0cdc1ad6c48faca403ea352bde73138443b5Mike Lockwood            name = values.getAsString(MediaStore.MediaColumns.TITLE);
1803242d0cdc1ad6c48faca403ea352bde73138443b5Mike Lockwood            if (name == null) {
1804242d0cdc1ad6c48faca403ea352bde73138443b5Mike Lockwood                // extract name from file name
1805242d0cdc1ad6c48faca403ea352bde73138443b5Mike Lockwood                int lastDot = path.lastIndexOf('.');
1806242d0cdc1ad6c48faca403ea352bde73138443b5Mike Lockwood                name = (lastDot < 0 ? path.substring(lastSlash + 1)
1807242d0cdc1ad6c48faca403ea352bde73138443b5Mike Lockwood                        : path.substring(lastSlash + 1, lastDot));
1808242d0cdc1ad6c48faca403ea352bde73138443b5Mike Lockwood            }
1809242d0cdc1ad6c48faca403ea352bde73138443b5Mike Lockwood        }
1810242d0cdc1ad6c48faca403ea352bde73138443b5Mike Lockwood
1811242d0cdc1ad6c48faca403ea352bde73138443b5Mike Lockwood        values.put(MediaStore.Audio.Playlists.NAME, name);
1812242d0cdc1ad6c48faca403ea352bde73138443b5Mike Lockwood        values.put(MediaStore.Audio.Playlists.DATE_MODIFIED, entry.mLastModified);
1813242d0cdc1ad6c48faca403ea352bde73138443b5Mike Lockwood
1814242d0cdc1ad6c48faca403ea352bde73138443b5Mike Lockwood        if (rowId == 0) {
1815caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood            values.put(MediaStore.Audio.Playlists.DATA, path);
181635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            uri = mMediaProvider.insert(mPackageName, mPlaylistsUri, values);
1817caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood            rowId = ContentUris.parseId(uri);
1818caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood            membersUri = Uri.withAppendedPath(uri, Playlists.Members.CONTENT_DIRECTORY);
1819caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood        } else {
1820caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood            uri = ContentUris.withAppendedId(mPlaylistsUri, rowId);
182135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            mMediaProvider.update(mPackageName, uri, values, null, null);
182220b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
1823caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood            // delete members of existing playlist
1824caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood            membersUri = Uri.withAppendedPath(uri, Playlists.Members.CONTENT_DIRECTORY);
182535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            mMediaProvider.delete(mPackageName, membersUri, null, null);
1826caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood        }
18279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1828caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood        String playListDirectory = path.substring(0, lastSlash + 1);
1829caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood        MediaFile.MediaFileType mediaFileType = MediaFile.getFileType(path);
1830caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood        int fileType = (mediaFileType == null ? 0 : mediaFileType.fileType);
183120b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
1832caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood        if (fileType == MediaFile.FILE_TYPE_M3U) {
1833c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen            processM3uPlayList(path, playListDirectory, membersUri, values, fileList);
1834caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood        } else if (fileType == MediaFile.FILE_TYPE_PLS) {
1835c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen            processPlsPlayList(path, playListDirectory, membersUri, values, fileList);
1836caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood        } else if (fileType == MediaFile.FILE_TYPE_WPL) {
18370b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen            processWplPlayList(path, playListDirectory, membersUri, values, fileList);
1838caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood        }
1839caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood    }
184020b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
1841caf7e43a40245520fc26b19bce408da24c050e01Mike Lockwood    private void processPlayLists() throws RemoteException {
184258ef68905d67e356eb6a05176863cacfbdca75c6Marco Nelissen        Iterator<FileEntry> iterator = mPlayLists.iterator();
1843c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen        Cursor fileList = null;
1844c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen        try {
184508f70fa5b82faa00d4d536b5a220d7ce8dd8f932Marco Nelissen            // use the files uri and projection because we need the format column,
184608f70fa5b82faa00d4d536b5a220d7ce8dd8f932Marco Nelissen            // but restrict the query to just audio files
184735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            fileList = mMediaProvider.query(mPackageName, mFilesUri, FILES_PRESCAN_PROJECTION,
184808f70fa5b82faa00d4d536b5a220d7ce8dd8f932Marco Nelissen                    "media_type=2", null, null, null);
1849c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen            while (iterator.hasNext()) {
1850c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen                FileEntry entry = iterator.next();
1851c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen                // only process playlist files if they are new or have been modified since the last scan
1852c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen                if (entry.mLastModifiedChanged) {
1853c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen                    processPlayList(entry, fileList);
1854c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen                }
1855c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen            }
1856c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen        } catch (RemoteException e1) {
1857c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen        } finally {
1858c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen            if (fileList != null) {
1859c164faa8314c110d417b653b9926de4803bb2ddaMarco Nelissen                fileList.close();
18609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
18619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
18629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
186320b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
1864c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood    private native void processDirectory(String path, MediaScannerClient client);
18659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private native void processFile(String path, String mimeType, MediaScannerClient client);
18669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public native void setLocale(String locale);
186720b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync
18689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public native byte[] extractAlbumArt(FileDescriptor fd);
18699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18704935d05eaa306cef88cf0ab13eca386f270409ecMarco Nelissen    private static native final void native_init();
18719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private native final void native_setup();
18729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private native final void native_finalize();
1873133cf8b92a07d5be8c64607b9644aa9cef169fb0James Dong
1874133cf8b92a07d5be8c64607b9644aa9cef169fb0James Dong    /**
18750b718392c1f50f45760b198a5d9e8df2cf2b5080Marco Nelissen     * Releases resources associated with this MediaScanner object.
1876133cf8b92a07d5be8c64607b9644aa9cef169fb0James Dong     * It is considered good practice to call this method when
1877133cf8b92a07d5be8c64607b9644aa9cef169fb0James Dong     * one is done using the MediaScanner object. After this method
1878133cf8b92a07d5be8c64607b9644aa9cef169fb0James Dong     * is called, the MediaScanner object can no longer be used.
1879133cf8b92a07d5be8c64607b9644aa9cef169fb0James Dong     */
1880133cf8b92a07d5be8c64607b9644aa9cef169fb0James Dong    public void release() {
1881133cf8b92a07d5be8c64607b9644aa9cef169fb0James Dong        native_finalize();
1882133cf8b92a07d5be8c64607b9644aa9cef169fb0James Dong    }
1883133cf8b92a07d5be8c64607b9644aa9cef169fb0James Dong
18849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
188520b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync    protected void finalize() {
18869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.getContentResolver().releaseProvider(mMediaProvider);
188720b03ea70bda3c4fb34e53cdf25cf98c4adb193frepo sync        native_finalize();
18889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
18899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1890