MtpDatabase.java revision 56c85244b9be0fc6f6c2baf5f9a53f2364d5ec5e
1d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood/*
2d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood * Copyright (C) 2010 The Android Open Source Project
3d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood *
4d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood * Licensed under the Apache License, Version 2.0 (the "License");
5d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood * you may not use this file except in compliance with the License.
6d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood * You may obtain a copy of the License at
7d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood *
8d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood *      http://www.apache.org/licenses/LICENSE-2.0
9d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood *
10d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood * Unless required by applicable law or agreed to in writing, software
11d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood * distributed under the License is distributed on an "AS IS" BASIS,
12d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood * See the License for the specific language governing permissions and
14d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood * limitations under the License.
15d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood */
16d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
170cd0136d440cf6ad9d5fab430269116786e671ecMike Lockwoodpackage android.mtp;
18d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
1956c85244b9be0fc6f6c2baf5f9a53f2364d5ec5eMike Lockwoodimport android.content.BroadcastReceiver;
20d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwoodimport android.content.Context;
21d815f79766984fce499e147ecbacc01914683f74Mike Lockwoodimport android.content.ContentValues;
22d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwoodimport android.content.IContentProvider;
232837eefc5459427138c080d445bb491c75630163Mike Lockwoodimport android.content.Intent;
2456c85244b9be0fc6f6c2baf5f9a53f2364d5ec5eMike Lockwoodimport android.content.IntentFilter;
25775de951a8d4f4fe58c849efd9ef7b92c4ade907Mike Lockwoodimport android.content.SharedPreferences;
26d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwoodimport android.database.Cursor;
2759e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwoodimport android.database.sqlite.SQLiteDatabase;
280cd0136d440cf6ad9d5fab430269116786e671ecMike Lockwoodimport android.media.MediaScanner;
29d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwoodimport android.net.Uri;
3056c85244b9be0fc6f6c2baf5f9a53f2364d5ec5eMike Lockwoodimport android.os.BatteryManager;
3156c85244b9be0fc6f6c2baf5f9a53f2364d5ec5eMike Lockwoodimport android.os.BatteryStats;
32d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwoodimport android.os.RemoteException;
33a31560598af25d5116effc2a6af0d9be12a0628dMike Lockwoodimport android.provider.MediaStore;
349a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwoodimport android.provider.MediaStore.Audio;
353b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwoodimport android.provider.MediaStore.Files;
36ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwoodimport android.provider.MediaStore.MediaColumns;
37d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwoodimport android.util.Log;
38ea93fa16b166ff477e9cf6bd3ac67c8fb259fb57Mike Lockwoodimport android.view.Display;
39ea93fa16b166ff477e9cf6bd3ac67c8fb259fb57Mike Lockwoodimport android.view.WindowManager;
40d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
415ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwoodimport java.io.File;
427d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwoodimport java.util.HashMap;
43fe464a76d8fc858be971dbb5e67b1d22fd925347dujin.chaimport java.util.Locale;
445ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood
45d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood/**
46d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood * {@hide}
47d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood */
48d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwoodpublic class MtpDatabase {
49d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
50d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private static final String TAG = "MtpDatabase";
51d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
522837eefc5459427138c080d445bb491c75630163Mike Lockwood    private final Context mContext;
5335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn    private final String mPackageName;
54d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private final IContentProvider mMediaProvider;
55d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private final String mVolumeName;
56d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private final Uri mObjectsUri;
5773e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood    // path to primary storage
5873e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood    private final String mMediaStoragePath;
5973e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood    // if not null, restrict all queries to these subdirectories
6073e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood    private final String[] mSubDirectories;
6173e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood    // where clause for restricting queries to files in mSubDirectories
6273e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood    private String mSubDirectoriesWhere;
6373e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood    // where arguments for restricting queries to files in mSubDirectories
6473e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood    private String[] mSubDirectoriesWhereArgs;
6573e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood
66b239b683765f63d79e74b8ba2a8cc2855f236536Mike Lockwood    private final HashMap<String, MtpStorage> mStorageMap = new HashMap<String, MtpStorage>();
67d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
687d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood    // cached property groups for single properties
697d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood    private final HashMap<Integer, MtpPropertyGroup> mPropertyGroupsByProperty
707d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood            = new HashMap<Integer, MtpPropertyGroup>();
717d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood
727d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood    // cached property groups for all properties for a given format
737d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood    private final HashMap<Integer, MtpPropertyGroup> mPropertyGroupsByFormat
747d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood            = new HashMap<Integer, MtpPropertyGroup>();
757d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood
762837eefc5459427138c080d445bb491c75630163Mike Lockwood    // true if the database has been modified in the current MTP session
772837eefc5459427138c080d445bb491c75630163Mike Lockwood    private boolean mDatabaseModified;
782837eefc5459427138c080d445bb491c75630163Mike Lockwood
79775de951a8d4f4fe58c849efd9ef7b92c4ade907Mike Lockwood    // SharedPreferences for writable MTP device properties
80775de951a8d4f4fe58c849efd9ef7b92c4ade907Mike Lockwood    private SharedPreferences mDeviceProperties;
8159e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood    private static final int DEVICE_PROPERTIES_DATABASE_VERSION = 1;
8259e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood
83d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private static final String[] ID_PROJECTION = new String[] {
843b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood            Files.FileColumns._ID, // 0
85d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    };
866a6a3aff17e057eeb1457ac4d04ab4b5e8f53abeMike Lockwood    private static final String[] PATH_PROJECTION = new String[] {
875ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood            Files.FileColumns._ID, // 0
885ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood            Files.FileColumns.DATA, // 1
895ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood    };
90f6f16614574767263fcd0073f72c099edaca0607Mike Lockwood    private static final String[] PATH_FORMAT_PROJECTION = new String[] {
913b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood            Files.FileColumns._ID, // 0
923b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood            Files.FileColumns.DATA, // 1
93f6f16614574767263fcd0073f72c099edaca0607Mike Lockwood            Files.FileColumns.FORMAT, // 2
94d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    };
95d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private static final String[] OBJECT_INFO_PROJECTION = new String[] {
963b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood            Files.FileColumns._ID, // 0
97b239b683765f63d79e74b8ba2a8cc2855f236536Mike Lockwood            Files.FileColumns.STORAGE_ID, // 1
983b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood            Files.FileColumns.FORMAT, // 2
993b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood            Files.FileColumns.PARENT, // 3
100b239b683765f63d79e74b8ba2a8cc2855f236536Mike Lockwood            Files.FileColumns.DATA, // 4
1011341f1eee3493fc5e263494acb8adebb6f0180b6Mike Lockwood            Files.FileColumns.DATE_ADDED, // 5
1021341f1eee3493fc5e263494acb8adebb6f0180b6Mike Lockwood            Files.FileColumns.DATE_MODIFIED, // 6
103d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    };
1043b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood    private static final String ID_WHERE = Files.FileColumns._ID + "=?";
105bafca214eaf326441e5157d645b2ee7fe8c7d1abMike Lockwood    private static final String PATH_WHERE = Files.FileColumns.DATA + "=?";
1066acc90fc216530f0a5bbf7339066af9b415cbb02Mike Lockwood
1076acc90fc216530f0a5bbf7339066af9b415cbb02Mike Lockwood    private static final String STORAGE_WHERE = Files.FileColumns.STORAGE_ID + "=?";
10858e6831ccb54b33a914115e88ebb67e720615fb8Mike Lockwood    private static final String FORMAT_WHERE = Files.FileColumns.FORMAT + "=?";
10958e6831ccb54b33a914115e88ebb67e720615fb8Mike Lockwood    private static final String PARENT_WHERE = Files.FileColumns.PARENT + "=?";
1106acc90fc216530f0a5bbf7339066af9b415cbb02Mike Lockwood    private static final String STORAGE_FORMAT_WHERE = STORAGE_WHERE + " AND "
111b239b683765f63d79e74b8ba2a8cc2855f236536Mike Lockwood                                            + Files.FileColumns.FORMAT + "=?";
1126acc90fc216530f0a5bbf7339066af9b415cbb02Mike Lockwood    private static final String STORAGE_PARENT_WHERE = STORAGE_WHERE + " AND "
1136acc90fc216530f0a5bbf7339066af9b415cbb02Mike Lockwood                                            + Files.FileColumns.PARENT + "=?";
1146acc90fc216530f0a5bbf7339066af9b415cbb02Mike Lockwood    private static final String FORMAT_PARENT_WHERE = FORMAT_WHERE + " AND "
1156acc90fc216530f0a5bbf7339066af9b415cbb02Mike Lockwood                                            + Files.FileColumns.PARENT + "=?";
1166acc90fc216530f0a5bbf7339066af9b415cbb02Mike Lockwood    private static final String STORAGE_FORMAT_PARENT_WHERE = STORAGE_FORMAT_WHERE + " AND "
1176acc90fc216530f0a5bbf7339066af9b415cbb02Mike Lockwood                                            + Files.FileColumns.PARENT + "=?";
118d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
119d815f79766984fce499e147ecbacc01914683f74Mike Lockwood    private final MediaScanner mMediaScanner;
12056c85244b9be0fc6f6c2baf5f9a53f2364d5ec5eMike Lockwood    private MtpServer mServer;
12156c85244b9be0fc6f6c2baf5f9a53f2364d5ec5eMike Lockwood
12256c85244b9be0fc6f6c2baf5f9a53f2364d5ec5eMike Lockwood    // read from native code
12356c85244b9be0fc6f6c2baf5f9a53f2364d5ec5eMike Lockwood    private int mBatteryLevel;
12456c85244b9be0fc6f6c2baf5f9a53f2364d5ec5eMike Lockwood    private int mBatteryScale;
125d815f79766984fce499e147ecbacc01914683f74Mike Lockwood
126d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    static {
127d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        System.loadLibrary("media_jni");
128d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    }
129d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
13056c85244b9be0fc6f6c2baf5f9a53f2364d5ec5eMike Lockwood    private BroadcastReceiver mBatteryReceiver = new BroadcastReceiver() {
13156c85244b9be0fc6f6c2baf5f9a53f2364d5ec5eMike Lockwood          @Override
13256c85244b9be0fc6f6c2baf5f9a53f2364d5ec5eMike Lockwood        public void onReceive(Context context, Intent intent) {
13356c85244b9be0fc6f6c2baf5f9a53f2364d5ec5eMike Lockwood            String action = intent.getAction();
13456c85244b9be0fc6f6c2baf5f9a53f2364d5ec5eMike Lockwood            if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
13556c85244b9be0fc6f6c2baf5f9a53f2364d5ec5eMike Lockwood                mBatteryScale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, 0);
13656c85244b9be0fc6f6c2baf5f9a53f2364d5ec5eMike Lockwood                int newLevel = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
13756c85244b9be0fc6f6c2baf5f9a53f2364d5ec5eMike Lockwood                if (newLevel != mBatteryLevel) {
13856c85244b9be0fc6f6c2baf5f9a53f2364d5ec5eMike Lockwood                    mBatteryLevel = newLevel;
13956c85244b9be0fc6f6c2baf5f9a53f2364d5ec5eMike Lockwood                    if (mServer != null) {
14056c85244b9be0fc6f6c2baf5f9a53f2364d5ec5eMike Lockwood                        // send device property changed event
14156c85244b9be0fc6f6c2baf5f9a53f2364d5ec5eMike Lockwood                        mServer.sendDevicePropertyChanged(
14256c85244b9be0fc6f6c2baf5f9a53f2364d5ec5eMike Lockwood                                MtpConstants.DEVICE_PROPERTY_BATTERY_LEVEL);
14356c85244b9be0fc6f6c2baf5f9a53f2364d5ec5eMike Lockwood                    }
14456c85244b9be0fc6f6c2baf5f9a53f2364d5ec5eMike Lockwood                }
14556c85244b9be0fc6f6c2baf5f9a53f2364d5ec5eMike Lockwood            }
14656c85244b9be0fc6f6c2baf5f9a53f2364d5ec5eMike Lockwood        }
14756c85244b9be0fc6f6c2baf5f9a53f2364d5ec5eMike Lockwood    };
14856c85244b9be0fc6f6c2baf5f9a53f2364d5ec5eMike Lockwood
14973e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood    public MtpDatabase(Context context, String volumeName, String storagePath,
15073e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood            String[] subDirectories) {
151d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        native_setup();
152d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
1532837eefc5459427138c080d445bb491c75630163Mike Lockwood        mContext = context;
15435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        mPackageName = context.getPackageName();
155d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        mMediaProvider = context.getContentResolver().acquireProvider("media");
156d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        mVolumeName = volumeName;
15701788562f26f213f63c14483fd3977e23b8314abMike Lockwood        mMediaStoragePath = storagePath;
1588490e66f57506d4e4b05e7c987c7ca34295843e6Mike Lockwood        mObjectsUri = Files.getMtpObjectsUri(volumeName);
159d815f79766984fce499e147ecbacc01914683f74Mike Lockwood        mMediaScanner = new MediaScanner(context);
160fe464a76d8fc858be971dbb5e67b1d22fd925347dujin.cha
16173e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood        mSubDirectories = subDirectories;
16273e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood        if (subDirectories != null) {
16373e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood            // Compute "where" string for restricting queries to subdirectories
16473e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood            StringBuilder builder = new StringBuilder();
16573e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood            builder.append("(");
16673e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood            int count = subDirectories.length;
16773e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood            for (int i = 0; i < count; i++) {
16873e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                builder.append(Files.FileColumns.DATA + "=? OR "
16973e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                        + Files.FileColumns.DATA + " LIKE ?");
17073e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                if (i != count - 1) {
17173e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                    builder.append(" OR ");
17273e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                }
17373e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood            }
17473e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood            builder.append(")");
17573e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood            mSubDirectoriesWhere = builder.toString();
17673e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood
17773e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood            // Compute "where" arguments for restricting queries to subdirectories
17873e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood            mSubDirectoriesWhereArgs = new String[count * 2];
17973e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood            for (int i = 0, j = 0; i < count; i++) {
18073e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                String path = subDirectories[i];
18173e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                mSubDirectoriesWhereArgs[j++] = path;
18273e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                mSubDirectoriesWhereArgs[j++] = path + "/%";
18373e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood            }
18473e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood        }
18573e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood
186fe464a76d8fc858be971dbb5e67b1d22fd925347dujin.cha        // Set locale to MediaScanner.
187fe464a76d8fc858be971dbb5e67b1d22fd925347dujin.cha        Locale locale = context.getResources().getConfiguration().locale;
188fe464a76d8fc858be971dbb5e67b1d22fd925347dujin.cha        if (locale != null) {
189fe464a76d8fc858be971dbb5e67b1d22fd925347dujin.cha            String language = locale.getLanguage();
190fe464a76d8fc858be971dbb5e67b1d22fd925347dujin.cha            String country = locale.getCountry();
191fe464a76d8fc858be971dbb5e67b1d22fd925347dujin.cha            if (language != null) {
192fe464a76d8fc858be971dbb5e67b1d22fd925347dujin.cha                if (country != null) {
193fe464a76d8fc858be971dbb5e67b1d22fd925347dujin.cha                    mMediaScanner.setLocale(language + "_" + country);
194fe464a76d8fc858be971dbb5e67b1d22fd925347dujin.cha                } else {
195fe464a76d8fc858be971dbb5e67b1d22fd925347dujin.cha                    mMediaScanner.setLocale(language);
196fe464a76d8fc858be971dbb5e67b1d22fd925347dujin.cha                }
197fe464a76d8fc858be971dbb5e67b1d22fd925347dujin.cha            }
198fe464a76d8fc858be971dbb5e67b1d22fd925347dujin.cha        }
199775de951a8d4f4fe58c849efd9ef7b92c4ade907Mike Lockwood        initDeviceProperties(context);
200d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    }
201d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
20256c85244b9be0fc6f6c2baf5f9a53f2364d5ec5eMike Lockwood    public void setServer(MtpServer server) {
20356c85244b9be0fc6f6c2baf5f9a53f2364d5ec5eMike Lockwood        mServer = server;
20456c85244b9be0fc6f6c2baf5f9a53f2364d5ec5eMike Lockwood
20556c85244b9be0fc6f6c2baf5f9a53f2364d5ec5eMike Lockwood        // register for battery notifications when we are connected
20656c85244b9be0fc6f6c2baf5f9a53f2364d5ec5eMike Lockwood        if (server != null) {
20756c85244b9be0fc6f6c2baf5f9a53f2364d5ec5eMike Lockwood            mContext.registerReceiver(mBatteryReceiver,
20856c85244b9be0fc6f6c2baf5f9a53f2364d5ec5eMike Lockwood                    new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
20956c85244b9be0fc6f6c2baf5f9a53f2364d5ec5eMike Lockwood        } else {
21056c85244b9be0fc6f6c2baf5f9a53f2364d5ec5eMike Lockwood            mContext.unregisterReceiver(mBatteryReceiver);
21156c85244b9be0fc6f6c2baf5f9a53f2364d5ec5eMike Lockwood        }
21256c85244b9be0fc6f6c2baf5f9a53f2364d5ec5eMike Lockwood    }
21356c85244b9be0fc6f6c2baf5f9a53f2364d5ec5eMike Lockwood
214d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    @Override
215dbead321daf2c16dc74e182bec591b278cfccb2cMike Lockwood    protected void finalize() throws Throwable {
216dbead321daf2c16dc74e182bec591b278cfccb2cMike Lockwood        try {
217dbead321daf2c16dc74e182bec591b278cfccb2cMike Lockwood            native_finalize();
218dbead321daf2c16dc74e182bec591b278cfccb2cMike Lockwood        } finally {
219dbead321daf2c16dc74e182bec591b278cfccb2cMike Lockwood            super.finalize();
220dbead321daf2c16dc74e182bec591b278cfccb2cMike Lockwood        }
221d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    }
222d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
223b239b683765f63d79e74b8ba2a8cc2855f236536Mike Lockwood    public void addStorage(MtpStorage storage) {
224b239b683765f63d79e74b8ba2a8cc2855f236536Mike Lockwood        mStorageMap.put(storage.getPath(), storage);
225b239b683765f63d79e74b8ba2a8cc2855f236536Mike Lockwood    }
226b239b683765f63d79e74b8ba2a8cc2855f236536Mike Lockwood
227b239b683765f63d79e74b8ba2a8cc2855f236536Mike Lockwood    public void removeStorage(MtpStorage storage) {
228b239b683765f63d79e74b8ba2a8cc2855f236536Mike Lockwood        mStorageMap.remove(storage.getPath());
229b239b683765f63d79e74b8ba2a8cc2855f236536Mike Lockwood    }
230b239b683765f63d79e74b8ba2a8cc2855f236536Mike Lockwood
231775de951a8d4f4fe58c849efd9ef7b92c4ade907Mike Lockwood    private void initDeviceProperties(Context context) {
232775de951a8d4f4fe58c849efd9ef7b92c4ade907Mike Lockwood        final String devicePropertiesName = "device-properties";
233775de951a8d4f4fe58c849efd9ef7b92c4ade907Mike Lockwood        mDeviceProperties = context.getSharedPreferences(devicePropertiesName, Context.MODE_PRIVATE);
234775de951a8d4f4fe58c849efd9ef7b92c4ade907Mike Lockwood        File databaseFile = context.getDatabasePath(devicePropertiesName);
235775de951a8d4f4fe58c849efd9ef7b92c4ade907Mike Lockwood
236775de951a8d4f4fe58c849efd9ef7b92c4ade907Mike Lockwood        if (databaseFile.exists()) {
237775de951a8d4f4fe58c849efd9ef7b92c4ade907Mike Lockwood            // for backward compatibility - read device properties from sqlite database
238775de951a8d4f4fe58c849efd9ef7b92c4ade907Mike Lockwood            // and migrate them to shared prefs
239775de951a8d4f4fe58c849efd9ef7b92c4ade907Mike Lockwood            SQLiteDatabase db = null;
240775de951a8d4f4fe58c849efd9ef7b92c4ade907Mike Lockwood            Cursor c = null;
241775de951a8d4f4fe58c849efd9ef7b92c4ade907Mike Lockwood            try {
242775de951a8d4f4fe58c849efd9ef7b92c4ade907Mike Lockwood                db = context.openOrCreateDatabase("device-properties", Context.MODE_PRIVATE, null);
243775de951a8d4f4fe58c849efd9ef7b92c4ade907Mike Lockwood                if (db != null) {
244775de951a8d4f4fe58c849efd9ef7b92c4ade907Mike Lockwood                    c = db.query("properties", new String[] { "_id", "code", "value" },
245775de951a8d4f4fe58c849efd9ef7b92c4ade907Mike Lockwood                            null, null, null, null, null);
246775de951a8d4f4fe58c849efd9ef7b92c4ade907Mike Lockwood                    if (c != null) {
247775de951a8d4f4fe58c849efd9ef7b92c4ade907Mike Lockwood                        SharedPreferences.Editor e = mDeviceProperties.edit();
248775de951a8d4f4fe58c849efd9ef7b92c4ade907Mike Lockwood                        while (c.moveToNext()) {
249775de951a8d4f4fe58c849efd9ef7b92c4ade907Mike Lockwood                            String name = c.getString(1);
250775de951a8d4f4fe58c849efd9ef7b92c4ade907Mike Lockwood                            String value = c.getString(2);
251775de951a8d4f4fe58c849efd9ef7b92c4ade907Mike Lockwood                            e.putString(name, value);
252775de951a8d4f4fe58c849efd9ef7b92c4ade907Mike Lockwood                        }
253775de951a8d4f4fe58c849efd9ef7b92c4ade907Mike Lockwood                        e.commit();
254775de951a8d4f4fe58c849efd9ef7b92c4ade907Mike Lockwood                    }
255775de951a8d4f4fe58c849efd9ef7b92c4ade907Mike Lockwood                }
256775de951a8d4f4fe58c849efd9ef7b92c4ade907Mike Lockwood            } catch (Exception e) {
257775de951a8d4f4fe58c849efd9ef7b92c4ade907Mike Lockwood                Log.e(TAG, "failed to migrate device properties", e);
258775de951a8d4f4fe58c849efd9ef7b92c4ade907Mike Lockwood            } finally {
259775de951a8d4f4fe58c849efd9ef7b92c4ade907Mike Lockwood                if (c != null) c.close();
260775de951a8d4f4fe58c849efd9ef7b92c4ade907Mike Lockwood                if (db != null) db.close();
261775de951a8d4f4fe58c849efd9ef7b92c4ade907Mike Lockwood            }
2623ed02535fdc3c752346c40b57962905b7072e693jangwon.lee            context.deleteDatabase(devicePropertiesName);
26359e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood        }
26459e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood    }
26559e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood
26673e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood    // check to see if the path is contained in one of our storage subdirectories
26773e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood    // returns true if we have no special subdirectories
26873e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood    private boolean inStorageSubDirectory(String path) {
26973e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood        if (mSubDirectories == null) return true;
27073e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood        if (path == null) return false;
27173e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood
27273e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood        boolean allowed = false;
27373e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood        int pathLength = path.length();
27473e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood        for (int i = 0; i < mSubDirectories.length && !allowed; i++) {
27573e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood            String subdir = mSubDirectories[i];
27673e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood            int subdirLength = subdir.length();
27773e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood            if (subdirLength < pathLength &&
27873e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                    path.charAt(subdirLength) == '/' &&
27973e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                    path.startsWith(subdir)) {
28073e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                allowed = true;
28173e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood            }
28273e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood        }
28373e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood        return allowed;
28473e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood    }
28573e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood
28673e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood    // check to see if the path matches one of our storage subdirectories
28773e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood    // returns true if we have no special subdirectories
28873e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood    private boolean isStorageSubDirectory(String path) {
28973e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood    if (mSubDirectories == null) return false;
29073e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood        for (int i = 0; i < mSubDirectories.length; i++) {
29173e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood            if (path.equals(mSubDirectories[i])) {
29273e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                return true;
29373e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood            }
29473e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood        }
29573e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood        return false;
29673e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood    }
29773e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood
298d815f79766984fce499e147ecbacc01914683f74Mike Lockwood    private int beginSendObject(String path, int format, int parent,
299b239b683765f63d79e74b8ba2a8cc2855f236536Mike Lockwood                         int storageId, long size, long modified) {
30073e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood        // if mSubDirectories is not null, do not allow copying files to any other locations
30173e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood        if (!inStorageSubDirectory(path)) return -1;
30273e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood
30373e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood        // make sure the object does not exist
304bafca214eaf326441e5157d645b2ee7fe8c7d1abMike Lockwood        if (path != null) {
305bafca214eaf326441e5157d645b2ee7fe8c7d1abMike Lockwood            Cursor c = null;
306bafca214eaf326441e5157d645b2ee7fe8c7d1abMike Lockwood            try {
30735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                c = mMediaProvider.query(mPackageName, mObjectsUri, ID_PROJECTION, PATH_WHERE,
30875ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown                        new String[] { path }, null, null);
309bafca214eaf326441e5157d645b2ee7fe8c7d1abMike Lockwood                if (c != null && c.getCount() > 0) {
310bafca214eaf326441e5157d645b2ee7fe8c7d1abMike Lockwood                    Log.w(TAG, "file already exists in beginSendObject: " + path);
311bafca214eaf326441e5157d645b2ee7fe8c7d1abMike Lockwood                    return -1;
312bafca214eaf326441e5157d645b2ee7fe8c7d1abMike Lockwood                }
313bafca214eaf326441e5157d645b2ee7fe8c7d1abMike Lockwood            } catch (RemoteException e) {
314bafca214eaf326441e5157d645b2ee7fe8c7d1abMike Lockwood                Log.e(TAG, "RemoteException in beginSendObject", e);
315bafca214eaf326441e5157d645b2ee7fe8c7d1abMike Lockwood            } finally {
316bafca214eaf326441e5157d645b2ee7fe8c7d1abMike Lockwood                if (c != null) {
317bafca214eaf326441e5157d645b2ee7fe8c7d1abMike Lockwood                    c.close();
318bafca214eaf326441e5157d645b2ee7fe8c7d1abMike Lockwood                }
319bafca214eaf326441e5157d645b2ee7fe8c7d1abMike Lockwood            }
320bafca214eaf326441e5157d645b2ee7fe8c7d1abMike Lockwood        }
321bafca214eaf326441e5157d645b2ee7fe8c7d1abMike Lockwood
3222837eefc5459427138c080d445bb491c75630163Mike Lockwood        mDatabaseModified = true;
323d815f79766984fce499e147ecbacc01914683f74Mike Lockwood        ContentValues values = new ContentValues();
3243b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood        values.put(Files.FileColumns.DATA, path);
3253b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood        values.put(Files.FileColumns.FORMAT, format);
3263b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood        values.put(Files.FileColumns.PARENT, parent);
327b239b683765f63d79e74b8ba2a8cc2855f236536Mike Lockwood        values.put(Files.FileColumns.STORAGE_ID, storageId);
3283b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood        values.put(Files.FileColumns.SIZE, size);
3293b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood        values.put(Files.FileColumns.DATE_MODIFIED, modified);
330d815f79766984fce499e147ecbacc01914683f74Mike Lockwood
331d815f79766984fce499e147ecbacc01914683f74Mike Lockwood        try {
33235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            Uri uri = mMediaProvider.insert(mPackageName, mObjectsUri, values);
333d815f79766984fce499e147ecbacc01914683f74Mike Lockwood            if (uri != null) {
334d815f79766984fce499e147ecbacc01914683f74Mike Lockwood                return Integer.parseInt(uri.getPathSegments().get(2));
335d815f79766984fce499e147ecbacc01914683f74Mike Lockwood            } else {
336d815f79766984fce499e147ecbacc01914683f74Mike Lockwood                return -1;
337d815f79766984fce499e147ecbacc01914683f74Mike Lockwood            }
338d815f79766984fce499e147ecbacc01914683f74Mike Lockwood        } catch (RemoteException e) {
339d815f79766984fce499e147ecbacc01914683f74Mike Lockwood            Log.e(TAG, "RemoteException in beginSendObject", e);
340d815f79766984fce499e147ecbacc01914683f74Mike Lockwood            return -1;
341d815f79766984fce499e147ecbacc01914683f74Mike Lockwood        }
342d815f79766984fce499e147ecbacc01914683f74Mike Lockwood    }
343d815f79766984fce499e147ecbacc01914683f74Mike Lockwood
3447a0bd17bceaf3efc3732e30c538fae420d3b742cMike Lockwood    private void endSendObject(String path, int handle, int format, boolean succeeded) {
345d815f79766984fce499e147ecbacc01914683f74Mike Lockwood        if (succeeded) {
3469a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            // handle abstract playlists separately
3479a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            // they do not exist in the file system so don't use the media scanner here
3485367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood            if (format == MtpConstants.FORMAT_ABSTRACT_AV_PLAYLIST) {
3499a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                // extract name from path
3509a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                String name = path;
3519a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                int lastSlash = name.lastIndexOf('/');
3529a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                if (lastSlash >= 0) {
3539a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                    name = name.substring(lastSlash + 1);
3549a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                }
3558cc6eb1e4c708fb4398292ba30aa80ad5770d7ceMike Lockwood                // strip trailing ".pla" from the name
3568cc6eb1e4c708fb4398292ba30aa80ad5770d7ceMike Lockwood                if (name.endsWith(".pla")) {
3578cc6eb1e4c708fb4398292ba30aa80ad5770d7ceMike Lockwood                    name = name.substring(0, name.length() - 4);
3588cc6eb1e4c708fb4398292ba30aa80ad5770d7ceMike Lockwood                }
3599a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood
3609a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                ContentValues values = new ContentValues(1);
3619a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                values.put(Audio.Playlists.DATA, path);
3629a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                values.put(Audio.Playlists.NAME, name);
3630b58c19840c577c8d8fd8aa5315676d61b78ba0fMike Lockwood                values.put(Files.FileColumns.FORMAT, format);
3648ed67acf38ccdfdb89553ed58620a135f2100e10Mike Lockwood                values.put(Files.FileColumns.DATE_MODIFIED, System.currentTimeMillis() / 1000);
3659a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                values.put(MediaColumns.MEDIA_SCANNER_NEW_OBJECT_ID, handle);
3669a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                try {
36735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    Uri uri = mMediaProvider.insert(mPackageName,
36835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                            Audio.Playlists.EXTERNAL_CONTENT_URI, values);
3699a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                } catch (RemoteException e) {
3709a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                    Log.e(TAG, "RemoteException in endSendObject", e);
3719a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                }
3729a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            } else {
373c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood                mMediaScanner.scanMtpFile(path, mVolumeName, handle, format);
3749a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            }
375d815f79766984fce499e147ecbacc01914683f74Mike Lockwood        } else {
376d815f79766984fce499e147ecbacc01914683f74Mike Lockwood            deleteFile(handle);
377d815f79766984fce499e147ecbacc01914683f74Mike Lockwood        }
378d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    }
379d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
380b239b683765f63d79e74b8ba2a8cc2855f236536Mike Lockwood    private Cursor createObjectQuery(int storageID, int format, int parent) throws RemoteException {
38173e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood        String where;
38273e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood        String[] whereArgs;
38373e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood
3846acc90fc216530f0a5bbf7339066af9b415cbb02Mike Lockwood        if (storageID == 0xFFFFFFFF) {
3856acc90fc216530f0a5bbf7339066af9b415cbb02Mike Lockwood            // query all stores
3866acc90fc216530f0a5bbf7339066af9b415cbb02Mike Lockwood            if (format == 0) {
3876acc90fc216530f0a5bbf7339066af9b415cbb02Mike Lockwood                // query all formats
3886acc90fc216530f0a5bbf7339066af9b415cbb02Mike Lockwood                if (parent == 0) {
3896acc90fc216530f0a5bbf7339066af9b415cbb02Mike Lockwood                    // query all objects
39073e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                    where = null;
39173e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                    whereArgs = null;
39273e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                } else {
39373e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                    if (parent == 0xFFFFFFFF) {
39473e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                        // all objects in root of store
39573e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                        parent = 0;
39673e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                    }
39773e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                    where = PARENT_WHERE;
39873e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                    whereArgs = new String[] { Integer.toString(parent) };
3996acc90fc216530f0a5bbf7339066af9b415cbb02Mike Lockwood                }
400b239b683765f63d79e74b8ba2a8cc2855f236536Mike Lockwood            } else {
4016acc90fc216530f0a5bbf7339066af9b415cbb02Mike Lockwood                // query specific format
4026acc90fc216530f0a5bbf7339066af9b415cbb02Mike Lockwood                if (parent == 0) {
4036acc90fc216530f0a5bbf7339066af9b415cbb02Mike Lockwood                    // query all objects
40473e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                    where = FORMAT_WHERE;
40573e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                    whereArgs = new String[] { Integer.toString(format) };
40673e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                } else {
40773e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                    if (parent == 0xFFFFFFFF) {
40873e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                        // all objects in root of store
40973e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                        parent = 0;
41073e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                    }
41173e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                    where = FORMAT_PARENT_WHERE;
41273e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                    whereArgs = new String[] { Integer.toString(format),
41373e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                                               Integer.toString(parent) };
4146acc90fc216530f0a5bbf7339066af9b415cbb02Mike Lockwood                }
415b239b683765f63d79e74b8ba2a8cc2855f236536Mike Lockwood            }
416b239b683765f63d79e74b8ba2a8cc2855f236536Mike Lockwood        } else {
4176acc90fc216530f0a5bbf7339066af9b415cbb02Mike Lockwood            // query specific store
4186acc90fc216530f0a5bbf7339066af9b415cbb02Mike Lockwood            if (format == 0) {
4196acc90fc216530f0a5bbf7339066af9b415cbb02Mike Lockwood                // query all formats
4206acc90fc216530f0a5bbf7339066af9b415cbb02Mike Lockwood                if (parent == 0) {
4216acc90fc216530f0a5bbf7339066af9b415cbb02Mike Lockwood                    // query all objects
42273e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                    where = STORAGE_WHERE;
42373e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                    whereArgs = new String[] { Integer.toString(storageID) };
42473e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                } else {
42573e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                    if (parent == 0xFFFFFFFF) {
42673e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                        // all objects in root of store
42773e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                        parent = 0;
42873e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                    }
42973e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                    where = STORAGE_PARENT_WHERE;
43073e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                    whereArgs = new String[] { Integer.toString(storageID),
43173e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                                               Integer.toString(parent) };
4326acc90fc216530f0a5bbf7339066af9b415cbb02Mike Lockwood                }
433d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            } else {
4346acc90fc216530f0a5bbf7339066af9b415cbb02Mike Lockwood                // query specific format
4356acc90fc216530f0a5bbf7339066af9b415cbb02Mike Lockwood                if (parent == 0) {
4366acc90fc216530f0a5bbf7339066af9b415cbb02Mike Lockwood                    // query all objects
43773e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                    where = STORAGE_FORMAT_WHERE;
43873e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                    whereArgs = new String[] {  Integer.toString(storageID),
43973e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                                                Integer.toString(format) };
44073e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                } else {
44173e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                    if (parent == 0xFFFFFFFF) {
44273e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                        // all objects in root of store
44373e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                        parent = 0;
44473e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                    }
44573e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                    where = STORAGE_FORMAT_PARENT_WHERE;
44673e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                    whereArgs = new String[] { Integer.toString(storageID),
44773e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                                               Integer.toString(format),
44873e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                                               Integer.toString(parent) };
4496acc90fc216530f0a5bbf7339066af9b415cbb02Mike Lockwood                }
45073e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood            }
45173e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood        }
45273e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood
45373e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood        // if we are restricting queries to mSubDirectories, we need to add the restriction
45473e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood        // onto our "where" arguments
45573e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood        if (mSubDirectoriesWhere != null) {
45673e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood            if (where == null) {
45773e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                where = mSubDirectoriesWhere;
45873e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                whereArgs = mSubDirectoriesWhereArgs;
45973e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood            } else {
46073e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                where = where + " AND " + mSubDirectoriesWhere;
46173e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood
46273e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                // create new array to hold whereArgs and mSubDirectoriesWhereArgs
46373e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                String[] newWhereArgs =
46473e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                        new String[whereArgs.length + mSubDirectoriesWhereArgs.length];
46573e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                int i, j;
46673e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                for (i = 0; i < whereArgs.length; i++) {
46773e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                    newWhereArgs[i] = whereArgs[i];
4686acc90fc216530f0a5bbf7339066af9b415cbb02Mike Lockwood                }
46973e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                for (j = 0; j < mSubDirectoriesWhereArgs.length; i++, j++) {
47073e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                    newWhereArgs[i] = mSubDirectoriesWhereArgs[j];
47173e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                }
47273e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                whereArgs = newWhereArgs;
473d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            }
474b239b683765f63d79e74b8ba2a8cc2855f236536Mike Lockwood        }
47573e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood
47635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn        return mMediaProvider.query(mPackageName, mObjectsUri, ID_PROJECTION, where,
47735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                whereArgs, null, null);
478b239b683765f63d79e74b8ba2a8cc2855f236536Mike Lockwood    }
479b239b683765f63d79e74b8ba2a8cc2855f236536Mike Lockwood
480b239b683765f63d79e74b8ba2a8cc2855f236536Mike Lockwood    private int[] getObjectList(int storageID, int format, int parent) {
481b239b683765f63d79e74b8ba2a8cc2855f236536Mike Lockwood        Cursor c = null;
482b239b683765f63d79e74b8ba2a8cc2855f236536Mike Lockwood        try {
483b239b683765f63d79e74b8ba2a8cc2855f236536Mike Lockwood            c = createObjectQuery(storageID, format, parent);
484d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            if (c == null) {
485d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                return null;
486d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            }
487d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            int count = c.getCount();
488d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            if (count > 0) {
489d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                int[] result = new int[count];
490d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                for (int i = 0; i < count; i++) {
491d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                    c.moveToNext();
492d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                    result[i] = c.getInt(0);
493d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                }
494d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                return result;
495d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            }
496d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        } catch (RemoteException e) {
497d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            Log.e(TAG, "RemoteException in getObjectList", e);
498d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        } finally {
499d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            if (c != null) {
500d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                c.close();
501d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            }
502d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        }
503d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        return null;
504d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    }
505d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
5067a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood    private int getNumObjects(int storageID, int format, int parent) {
5077a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood        Cursor c = null;
5087a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood        try {
509b239b683765f63d79e74b8ba2a8cc2855f236536Mike Lockwood            c = createObjectQuery(storageID, format, parent);
5107a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood            if (c != null) {
5117a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood                return c.getCount();
5127a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood            }
5137a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood        } catch (RemoteException e) {
5147a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood            Log.e(TAG, "RemoteException in getNumObjects", e);
5157a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood        } finally {
5167a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood            if (c != null) {
5177a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood                c.close();
5187a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood            }
5197a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood        }
5207a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood        return -1;
5217a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood    }
5227a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood
5234b322ce4fb86b5a7a6e50633a3a9f498ca8d4706Mike Lockwood    private int[] getSupportedPlaybackFormats() {
5244b322ce4fb86b5a7a6e50633a3a9f498ca8d4706Mike Lockwood        return new int[] {
525e521169ff5dc6cbe1762bd7a049d95b56cc657eeMike Lockwood            // allow transfering arbitrary files
526e521169ff5dc6cbe1762bd7a049d95b56cc657eeMike Lockwood            MtpConstants.FORMAT_UNDEFINED,
52712b8a99fc1d4acc427307a4a924bf33745410260Mike Lockwood
528792ec849e5bc27c090c62f578846b888fa43e0d6Mike Lockwood            MtpConstants.FORMAT_ASSOCIATION,
52912b8a99fc1d4acc427307a4a924bf33745410260Mike Lockwood            MtpConstants.FORMAT_TEXT,
53012b8a99fc1d4acc427307a4a924bf33745410260Mike Lockwood            MtpConstants.FORMAT_HTML,
53112b8a99fc1d4acc427307a4a924bf33745410260Mike Lockwood            MtpConstants.FORMAT_WAV,
53212b8a99fc1d4acc427307a4a924bf33745410260Mike Lockwood            MtpConstants.FORMAT_MP3,
53312b8a99fc1d4acc427307a4a924bf33745410260Mike Lockwood            MtpConstants.FORMAT_MPEG,
53412b8a99fc1d4acc427307a4a924bf33745410260Mike Lockwood            MtpConstants.FORMAT_EXIF_JPEG,
53512b8a99fc1d4acc427307a4a924bf33745410260Mike Lockwood            MtpConstants.FORMAT_TIFF_EP,
536240582eabee56d55751b85e220811d48fabe839abo huang            MtpConstants.FORMAT_BMP,
53712b8a99fc1d4acc427307a4a924bf33745410260Mike Lockwood            MtpConstants.FORMAT_GIF,
53812b8a99fc1d4acc427307a4a924bf33745410260Mike Lockwood            MtpConstants.FORMAT_JFIF,
53912b8a99fc1d4acc427307a4a924bf33745410260Mike Lockwood            MtpConstants.FORMAT_PNG,
54012b8a99fc1d4acc427307a4a924bf33745410260Mike Lockwood            MtpConstants.FORMAT_TIFF,
54112b8a99fc1d4acc427307a4a924bf33745410260Mike Lockwood            MtpConstants.FORMAT_WMA,
54212b8a99fc1d4acc427307a4a924bf33745410260Mike Lockwood            MtpConstants.FORMAT_OGG,
54312b8a99fc1d4acc427307a4a924bf33745410260Mike Lockwood            MtpConstants.FORMAT_AAC,
54412b8a99fc1d4acc427307a4a924bf33745410260Mike Lockwood            MtpConstants.FORMAT_MP4_CONTAINER,
54512b8a99fc1d4acc427307a4a924bf33745410260Mike Lockwood            MtpConstants.FORMAT_MP2,
54612b8a99fc1d4acc427307a4a924bf33745410260Mike Lockwood            MtpConstants.FORMAT_3GP_CONTAINER,
547792ec849e5bc27c090c62f578846b888fa43e0d6Mike Lockwood            MtpConstants.FORMAT_ABSTRACT_AV_PLAYLIST,
54812b8a99fc1d4acc427307a4a924bf33745410260Mike Lockwood            MtpConstants.FORMAT_WPL_PLAYLIST,
54912b8a99fc1d4acc427307a4a924bf33745410260Mike Lockwood            MtpConstants.FORMAT_M3U_PLAYLIST,
55012b8a99fc1d4acc427307a4a924bf33745410260Mike Lockwood            MtpConstants.FORMAT_PLS_PLAYLIST,
55112b8a99fc1d4acc427307a4a924bf33745410260Mike Lockwood            MtpConstants.FORMAT_XML_DOCUMENT,
552f9f223edb408cdc9fd946dc099a86857079a639fGlenn Kasten            MtpConstants.FORMAT_FLAC,
5534b322ce4fb86b5a7a6e50633a3a9f498ca8d4706Mike Lockwood        };
5544b322ce4fb86b5a7a6e50633a3a9f498ca8d4706Mike Lockwood    }
5554b322ce4fb86b5a7a6e50633a3a9f498ca8d4706Mike Lockwood
5564b322ce4fb86b5a7a6e50633a3a9f498ca8d4706Mike Lockwood    private int[] getSupportedCaptureFormats() {
5574b322ce4fb86b5a7a6e50633a3a9f498ca8d4706Mike Lockwood        // no capture formats yet
5584b322ce4fb86b5a7a6e50633a3a9f498ca8d4706Mike Lockwood        return null;
5594b322ce4fb86b5a7a6e50633a3a9f498ca8d4706Mike Lockwood    }
5604b322ce4fb86b5a7a6e50633a3a9f498ca8d4706Mike Lockwood
561ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood    static final int[] FILE_PROPERTIES = {
562ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            // NOTE must match beginning of AUDIO_PROPERTIES, VIDEO_PROPERTIES
563ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            // and IMAGE_PROPERTIES below
5645367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood            MtpConstants.PROPERTY_STORAGE_ID,
5655367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood            MtpConstants.PROPERTY_OBJECT_FORMAT,
566d3bfecb0c9bdf3651a06e86c7c8607768a29a9aeMike Lockwood            MtpConstants.PROPERTY_PROTECTION_STATUS,
5675367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood            MtpConstants.PROPERTY_OBJECT_SIZE,
5685367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood            MtpConstants.PROPERTY_OBJECT_FILE_NAME,
569d3bfecb0c9bdf3651a06e86c7c8607768a29a9aeMike Lockwood            MtpConstants.PROPERTY_DATE_MODIFIED,
5705367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood            MtpConstants.PROPERTY_PARENT_OBJECT,
571d3bfecb0c9bdf3651a06e86c7c8607768a29a9aeMike Lockwood            MtpConstants.PROPERTY_PERSISTENT_UID,
572d3bfecb0c9bdf3651a06e86c7c8607768a29a9aeMike Lockwood            MtpConstants.PROPERTY_NAME,
573ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_DATE_ADDED,
574ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood    };
575ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood
576ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood    static final int[] AUDIO_PROPERTIES = {
577ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            // NOTE must match FILE_PROPERTIES above
578ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_STORAGE_ID,
579ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_OBJECT_FORMAT,
580ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_PROTECTION_STATUS,
581ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_OBJECT_SIZE,
582ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_OBJECT_FILE_NAME,
583ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_DATE_MODIFIED,
584ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_PARENT_OBJECT,
585ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_PERSISTENT_UID,
586ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_NAME,
587ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_DISPLAY_NAME,
588ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_DATE_ADDED,
589ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood
590ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            // audio specific properties
591ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_ARTIST,
592ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_ALBUM_NAME,
593ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_ALBUM_ARTIST,
594ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_TRACK,
595ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_ORIGINAL_RELEASE_DATE,
596ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_DURATION,
597ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_GENRE,
598ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_COMPOSER,
599ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood    };
600ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood
601ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood    static final int[] VIDEO_PROPERTIES = {
602ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            // NOTE must match FILE_PROPERTIES above
603ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_STORAGE_ID,
604ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_OBJECT_FORMAT,
605ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_PROTECTION_STATUS,
606ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_OBJECT_SIZE,
607ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_OBJECT_FILE_NAME,
608ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_DATE_MODIFIED,
609ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_PARENT_OBJECT,
610ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_PERSISTENT_UID,
611ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_NAME,
612ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_DISPLAY_NAME,
613ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_DATE_ADDED,
614ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood
615ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            // video specific properties
616ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_ARTIST,
617ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_ALBUM_NAME,
618ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_DURATION,
619ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_DESCRIPTION,
620ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood    };
621ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood
622ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood    static final int[] IMAGE_PROPERTIES = {
623ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            // NOTE must match FILE_PROPERTIES above
624ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_STORAGE_ID,
625ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_OBJECT_FORMAT,
626ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_PROTECTION_STATUS,
627ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_OBJECT_SIZE,
628ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_OBJECT_FILE_NAME,
629ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_DATE_MODIFIED,
630ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_PARENT_OBJECT,
631ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_PERSISTENT_UID,
632ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_NAME,
633ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_DISPLAY_NAME,
634ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_DATE_ADDED,
635ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood
636ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            // image specific properties
637ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_DESCRIPTION,
638ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood    };
639ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood
6407d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood    static final int[] ALL_PROPERTIES = {
6417d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood            // NOTE must match FILE_PROPERTIES above
6427d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood            MtpConstants.PROPERTY_STORAGE_ID,
6437d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood            MtpConstants.PROPERTY_OBJECT_FORMAT,
6447d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood            MtpConstants.PROPERTY_PROTECTION_STATUS,
6457d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood            MtpConstants.PROPERTY_OBJECT_SIZE,
6467d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood            MtpConstants.PROPERTY_OBJECT_FILE_NAME,
6477d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood            MtpConstants.PROPERTY_DATE_MODIFIED,
6487d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood            MtpConstants.PROPERTY_PARENT_OBJECT,
6497d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood            MtpConstants.PROPERTY_PERSISTENT_UID,
6507d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood            MtpConstants.PROPERTY_NAME,
6517d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood            MtpConstants.PROPERTY_DISPLAY_NAME,
6527d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood            MtpConstants.PROPERTY_DATE_ADDED,
6537d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood
6547d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood            // image specific properties
6557d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood            MtpConstants.PROPERTY_DESCRIPTION,
6567d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood
6577d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood            // audio specific properties
6587d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood            MtpConstants.PROPERTY_ARTIST,
6597d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood            MtpConstants.PROPERTY_ALBUM_NAME,
6607d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood            MtpConstants.PROPERTY_ALBUM_ARTIST,
6617d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood            MtpConstants.PROPERTY_TRACK,
6627d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood            MtpConstants.PROPERTY_ORIGINAL_RELEASE_DATE,
6637d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood            MtpConstants.PROPERTY_DURATION,
6647d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood            MtpConstants.PROPERTY_GENRE,
6657d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood            MtpConstants.PROPERTY_COMPOSER,
6667d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood
6677d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood            // video specific properties
6687d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood            MtpConstants.PROPERTY_ARTIST,
6697d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood            MtpConstants.PROPERTY_ALBUM_NAME,
6707d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood            MtpConstants.PROPERTY_DURATION,
6717d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood            MtpConstants.PROPERTY_DESCRIPTION,
6727d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood
6737d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood            // image specific properties
6747d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood            MtpConstants.PROPERTY_DESCRIPTION,
6757d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood    };
6767d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood
677ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood    private int[] getSupportedObjectProperties(int format) {
678ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood        switch (format) {
679ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            case MtpConstants.FORMAT_MP3:
680ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            case MtpConstants.FORMAT_WAV:
681ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            case MtpConstants.FORMAT_WMA:
682ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            case MtpConstants.FORMAT_OGG:
683ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            case MtpConstants.FORMAT_AAC:
684ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                return AUDIO_PROPERTIES;
685ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            case MtpConstants.FORMAT_MPEG:
686ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            case MtpConstants.FORMAT_3GP_CONTAINER:
687ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            case MtpConstants.FORMAT_WMV:
688ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                return VIDEO_PROPERTIES;
689ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            case MtpConstants.FORMAT_EXIF_JPEG:
690ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            case MtpConstants.FORMAT_GIF:
691ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            case MtpConstants.FORMAT_PNG:
692ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            case MtpConstants.FORMAT_BMP:
693ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                return IMAGE_PROPERTIES;
6947d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood            case 0:
6957d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood                return ALL_PROPERTIES;
696ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            default:
697ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                return FILE_PROPERTIES;
698ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood        }
6994b322ce4fb86b5a7a6e50633a3a9f498ca8d4706Mike Lockwood    }
7004b322ce4fb86b5a7a6e50633a3a9f498ca8d4706Mike Lockwood
7014b322ce4fb86b5a7a6e50633a3a9f498ca8d4706Mike Lockwood    private int[] getSupportedDeviceProperties() {
70259e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood        return new int[] {
70359e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood            MtpConstants.DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER,
70459e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood            MtpConstants.DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME,
705ea93fa16b166ff477e9cf6bd3ac67c8fb259fb57Mike Lockwood            MtpConstants.DEVICE_PROPERTY_IMAGE_SIZE,
70656c85244b9be0fc6f6c2baf5f9a53f2364d5ec5eMike Lockwood            MtpConstants.DEVICE_PROPERTY_BATTERY_LEVEL,
70759e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood        };
7084b322ce4fb86b5a7a6e50633a3a9f498ca8d4706Mike Lockwood    }
7094b322ce4fb86b5a7a6e50633a3a9f498ca8d4706Mike Lockwood
710e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood
7117d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood    private MtpPropertyList getObjectPropertyList(long handle, int format, long property,
712e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood                        int groupCode, int depth) {
713e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood        // FIXME - implement group support
714e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood        if (groupCode != 0) {
715e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood            return new MtpPropertyList(0, MtpConstants.RESPONSE_SPECIFICATION_BY_GROUP_UNSUPPORTED);
7165ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood        }
7175ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood
7187d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood        MtpPropertyGroup propertyGroup;
7197d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood        if (property == 0xFFFFFFFFL) {
7207d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood             propertyGroup = mPropertyGroupsByFormat.get(format);
7217d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood             if (propertyGroup == null) {
7227d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood                int[] propertyList = getSupportedObjectProperties(format);
72335654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                propertyGroup = new MtpPropertyGroup(this, mMediaProvider, mPackageName,
72435654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        mVolumeName, propertyList);
7257d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood                mPropertyGroupsByFormat.put(new Integer(format), propertyGroup);
726e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood            }
7277d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood        } else {
7287d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood              propertyGroup = mPropertyGroupsByProperty.get(property);
7297d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood             if (propertyGroup == null) {
7307d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood                int[] propertyList = new int[] { (int)property };
73135654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                propertyGroup = new MtpPropertyGroup(this, mMediaProvider, mPackageName,
73235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        mVolumeName, propertyList);
7337d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood                mPropertyGroupsByProperty.put(new Integer((int)property), propertyGroup);
734e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood            }
735e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood        }
7367d7fb63071ca370f77ed69055ac30341b8388d15Mike Lockwood
737b239b683765f63d79e74b8ba2a8cc2855f236536Mike Lockwood        return propertyGroup.getPropertyList((int)handle, format, depth);
738e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood    }
739e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood
740e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood    private int renameFile(int handle, String newName) {
741e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood        Cursor c = null;
742e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood
743e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood        // first compute current path
744e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood        String path = null;
745e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood        String[] whereArgs = new String[] {  Integer.toString(handle) };
746e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood        try {
74735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            c = mMediaProvider.query(mPackageName, mObjectsUri, PATH_PROJECTION, ID_WHERE,
74835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    whereArgs, null, null);
749e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood            if (c != null && c.moveToNext()) {
7501c4e88d0b0a8deede0415183739478b5ebc12bfdMike Lockwood                path = c.getString(1);
751e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood            }
752e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood        } catch (RemoteException e) {
753e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood            Log.e(TAG, "RemoteException in getObjectFilePath", e);
754e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood            return MtpConstants.RESPONSE_GENERAL_ERROR;
755e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood        } finally {
756e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood            if (c != null) {
757e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood                c.close();
758b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood            }
759b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood        }
760e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood        if (path == null) {
761e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood            return MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE;
762e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood        }
763e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood
76473e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood        // do not allow renaming any of the special subdirectories
76573e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood        if (isStorageSubDirectory(path)) {
76673e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood            return MtpConstants.RESPONSE_OBJECT_WRITE_PROTECTED;
76773e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood        }
76873e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood
769e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood        // now rename the file.  make sure this succeeds before updating database
770e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood        File oldFile = new File(path);
771e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood        int lastSlash = path.lastIndexOf('/');
772e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood        if (lastSlash <= 1) {
773e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood            return MtpConstants.RESPONSE_GENERAL_ERROR;
774e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood        }
775e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood        String newPath = path.substring(0, lastSlash + 1) + newName;
776e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood        File newFile = new File(newPath);
777e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood        boolean success = oldFile.renameTo(newFile);
778e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood        if (!success) {
779f26a586c86b097f975e26fe526ead564ad011bd0Mike Lockwood            Log.w(TAG, "renaming "+ path + " to " + newPath + " failed");
780e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood            return MtpConstants.RESPONSE_GENERAL_ERROR;
781e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood        }
782e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood
783e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood        // finally update database
784e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood        ContentValues values = new ContentValues();
785e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood        values.put(Files.FileColumns.DATA, newPath);
786e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood        int updated = 0;
787e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood        try {
788e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood            // note - we are relying on a special case in MediaProvider.update() to update
789e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood            // the paths for all children in the case where this is a directory.
79035654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            updated = mMediaProvider.update(mPackageName, mObjectsUri, values, ID_WHERE, whereArgs);
791e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood        } catch (RemoteException e) {
792e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood            Log.e(TAG, "RemoteException in mMediaProvider.update", e);
793e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood        }
794e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood        if (updated == 0) {
795e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood            Log.e(TAG, "Unable to update path for " + path + " to " + newPath);
796e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood            // this shouldn't happen, but if it does we need to rename the file to its original name
797e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood            newFile.renameTo(oldFile);
798e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood            return MtpConstants.RESPONSE_GENERAL_ERROR;
799e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood        }
800e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood
801ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen        // check if nomedia status changed
802ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen        if (newFile.isDirectory()) {
803ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen            // for directories, check if renamed from something hidden to something non-hidden
804ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen            if (oldFile.getName().startsWith(".") && !newPath.startsWith(".")) {
805ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen                // directory was unhidden
806ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen                try {
80735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    mMediaProvider.call(mPackageName, MediaStore.UNHIDE_CALL, newPath, null);
808ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen                } catch (RemoteException e) {
809ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen                    Log.e(TAG, "failed to unhide/rescan for " + newPath);
810ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen                }
811ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen            }
812ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen        } else {
813ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen            // for files, check if renamed from .nomedia to something else
814ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen            if (oldFile.getName().toLowerCase(Locale.US).equals(".nomedia")
815ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen                    && !newPath.toLowerCase(Locale.US).equals(".nomedia")) {
816ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen                try {
81735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                    mMediaProvider.call(mPackageName, MediaStore.UNHIDE_CALL, oldFile.getParent(), null);
818ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen                } catch (RemoteException e) {
819ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen                    Log.e(TAG, "failed to unhide/rescan for " + newPath);
820ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen                }
821ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen            }
822ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen        }
823ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen
824e2ad6ec1718ef0c0e8230f8f62e7cfefcf598b6aMike Lockwood        return MtpConstants.RESPONSE_OK;
825d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    }
826d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
82759e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood    private int setObjectProperty(int handle, int property,
82859e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                            long intValue, String stringValue) {
8295ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood        switch (property) {
8305ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood            case MtpConstants.PROPERTY_OBJECT_FILE_NAME:
8315ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood                return renameFile(handle, stringValue);
8325ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood
8335ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood            default:
8345ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood                return MtpConstants.RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
8355ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood        }
83659e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood    }
83759e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood
83859e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood    private int getDeviceProperty(int property, long[] outIntValue, char[] outStringValue) {
83959e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood        switch (property) {
84059e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood            case MtpConstants.DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER:
84159e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood            case MtpConstants.DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME:
842775de951a8d4f4fe58c849efd9ef7b92c4ade907Mike Lockwood                // writable string properties kept in shared preferences
843775de951a8d4f4fe58c849efd9ef7b92c4ade907Mike Lockwood                String value = mDeviceProperties.getString(Integer.toString(property), "");
844775de951a8d4f4fe58c849efd9ef7b92c4ade907Mike Lockwood                int length = value.length();
845775de951a8d4f4fe58c849efd9ef7b92c4ade907Mike Lockwood                if (length > 255) {
846775de951a8d4f4fe58c849efd9ef7b92c4ade907Mike Lockwood                    length = 255;
84759e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                }
848775de951a8d4f4fe58c849efd9ef7b92c4ade907Mike Lockwood                value.getChars(0, length, outStringValue, 0);
849775de951a8d4f4fe58c849efd9ef7b92c4ade907Mike Lockwood                outStringValue[length] = 0;
850775de951a8d4f4fe58c849efd9ef7b92c4ade907Mike Lockwood                return MtpConstants.RESPONSE_OK;
85159e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood
852ea93fa16b166ff477e9cf6bd3ac67c8fb259fb57Mike Lockwood            case MtpConstants.DEVICE_PROPERTY_IMAGE_SIZE:
853ea93fa16b166ff477e9cf6bd3ac67c8fb259fb57Mike Lockwood                // use screen size as max image size
854ea93fa16b166ff477e9cf6bd3ac67c8fb259fb57Mike Lockwood                Display display = ((WindowManager)mContext.getSystemService(
855ea93fa16b166ff477e9cf6bd3ac67c8fb259fb57Mike Lockwood                        Context.WINDOW_SERVICE)).getDefaultDisplay();
85644bc17c6b517aef35a390c81b5aa79c4f284f744Dianne Hackborn                int width = display.getMaximumSizeDimension();
85744bc17c6b517aef35a390c81b5aa79c4f284f744Dianne Hackborn                int height = display.getMaximumSizeDimension();
858ea93fa16b166ff477e9cf6bd3ac67c8fb259fb57Mike Lockwood                String imageSize = Integer.toString(width) + "x" +  Integer.toString(height);
859ea93fa16b166ff477e9cf6bd3ac67c8fb259fb57Mike Lockwood                imageSize.getChars(0, imageSize.length(), outStringValue, 0);
860ea93fa16b166ff477e9cf6bd3ac67c8fb259fb57Mike Lockwood                outStringValue[imageSize.length()] = 0;
861ea93fa16b166ff477e9cf6bd3ac67c8fb259fb57Mike Lockwood                return MtpConstants.RESPONSE_OK;
862ea93fa16b166ff477e9cf6bd3ac67c8fb259fb57Mike Lockwood
86356c85244b9be0fc6f6c2baf5f9a53f2364d5ec5eMike Lockwood            // DEVICE_PROPERTY_BATTERY_LEVEL is implemented in the JNI code
86456c85244b9be0fc6f6c2baf5f9a53f2364d5ec5eMike Lockwood
865ea93fa16b166ff477e9cf6bd3ac67c8fb259fb57Mike Lockwood            default:
866ea93fa16b166ff477e9cf6bd3ac67c8fb259fb57Mike Lockwood                return MtpConstants.RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
867ea93fa16b166ff477e9cf6bd3ac67c8fb259fb57Mike Lockwood        }
86859e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood    }
86959e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood
87059e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood    private int setDeviceProperty(int property, long intValue, String stringValue) {
87159e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood        switch (property) {
87259e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood            case MtpConstants.DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER:
87359e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood            case MtpConstants.DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME:
874775de951a8d4f4fe58c849efd9ef7b92c4ade907Mike Lockwood                // writable string properties kept in shared prefs
875775de951a8d4f4fe58c849efd9ef7b92c4ade907Mike Lockwood                SharedPreferences.Editor e = mDeviceProperties.edit();
876775de951a8d4f4fe58c849efd9ef7b92c4ade907Mike Lockwood                e.putString(Integer.toString(property), stringValue);
877775de951a8d4f4fe58c849efd9ef7b92c4ade907Mike Lockwood                return (e.commit() ? MtpConstants.RESPONSE_OK
878775de951a8d4f4fe58c849efd9ef7b92c4ade907Mike Lockwood                        : MtpConstants.RESPONSE_GENERAL_ERROR);
87959e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood        }
88059e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood
88159e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood        return MtpConstants.RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
88259e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood    }
88359e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood
884d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private boolean getObjectInfo(int handle, int[] outStorageFormatParent,
8851341f1eee3493fc5e263494acb8adebb6f0180b6Mike Lockwood                        char[] outName, long[] outCreatedModified) {
886d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        Cursor c = null;
887d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        try {
88835654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            c = mMediaProvider.query(mPackageName, mObjectsUri, OBJECT_INFO_PROJECTION,
88975ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown                            ID_WHERE, new String[] {  Integer.toString(handle) }, null, null);
890d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            if (c != null && c.moveToNext()) {
891b239b683765f63d79e74b8ba2a8cc2855f236536Mike Lockwood                outStorageFormatParent[0] = c.getInt(1);
892d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                outStorageFormatParent[1] = c.getInt(2);
893d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                outStorageFormatParent[2] = c.getInt(3);
894d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
895d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                // extract name from path
896b239b683765f63d79e74b8ba2a8cc2855f236536Mike Lockwood                String path = c.getString(4);
897d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                int lastSlash = path.lastIndexOf('/');
898d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                int start = (lastSlash >= 0 ? lastSlash + 1 : 0);
899d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                int end = path.length();
900d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                if (end - start > 255) {
901d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                    end = start + 255;
902d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                }
903d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                path.getChars(start, end, outName, 0);
904d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                outName[end - start] = 0;
905d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
9061341f1eee3493fc5e263494acb8adebb6f0180b6Mike Lockwood                outCreatedModified[0] = c.getLong(5);
9071341f1eee3493fc5e263494acb8adebb6f0180b6Mike Lockwood                outCreatedModified[1] = c.getLong(6);
9081341f1eee3493fc5e263494acb8adebb6f0180b6Mike Lockwood                // use modification date as creation date if date added is not set
9091341f1eee3493fc5e263494acb8adebb6f0180b6Mike Lockwood                if (outCreatedModified[0] == 0) {
9101341f1eee3493fc5e263494acb8adebb6f0180b6Mike Lockwood                    outCreatedModified[0] = outCreatedModified[1];
9111341f1eee3493fc5e263494acb8adebb6f0180b6Mike Lockwood                }
912d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                return true;
913d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            }
914d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        } catch (RemoteException e) {
9152b5f9ad1eaf0d6daaca5cf3761434a09309902bbMike Lockwood            Log.e(TAG, "RemoteException in getObjectInfo", e);
916d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        } finally {
917d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            if (c != null) {
918d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                c.close();
919d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            }
920d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        }
921d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        return false;
922d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    }
923d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
924365e03e4943b2d2f4d1e602409ab0e770ea77d1dMike Lockwood    private int getObjectFilePath(int handle, char[] outFilePath, long[] outFileLengthFormat) {
92501788562f26f213f63c14483fd3977e23b8314abMike Lockwood        if (handle == 0) {
92601788562f26f213f63c14483fd3977e23b8314abMike Lockwood            // special case root directory
92701788562f26f213f63c14483fd3977e23b8314abMike Lockwood            mMediaStoragePath.getChars(0, mMediaStoragePath.length(), outFilePath, 0);
92801788562f26f213f63c14483fd3977e23b8314abMike Lockwood            outFilePath[mMediaStoragePath.length()] = 0;
929365e03e4943b2d2f4d1e602409ab0e770ea77d1dMike Lockwood            outFileLengthFormat[0] = 0;
930365e03e4943b2d2f4d1e602409ab0e770ea77d1dMike Lockwood            outFileLengthFormat[1] = MtpConstants.FORMAT_ASSOCIATION;
93101788562f26f213f63c14483fd3977e23b8314abMike Lockwood            return MtpConstants.RESPONSE_OK;
93201788562f26f213f63c14483fd3977e23b8314abMike Lockwood        }
933d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        Cursor c = null;
934d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        try {
93535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            c = mMediaProvider.query(mPackageName, mObjectsUri, PATH_FORMAT_PROJECTION,
93675ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown                            ID_WHERE, new String[] {  Integer.toString(handle) }, null, null);
937d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            if (c != null && c.moveToNext()) {
9381c4e88d0b0a8deede0415183739478b5ebc12bfdMike Lockwood                String path = c.getString(1);
939d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                path.getChars(0, path.length(), outFilePath, 0);
940d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                outFilePath[path.length()] = 0;
941f6f16614574767263fcd0073f72c099edaca0607Mike Lockwood                // File transfers from device to host will likely fail if the size is incorrect.
942f6f16614574767263fcd0073f72c099edaca0607Mike Lockwood                // So to be safe, use the actual file size here.
943f6f16614574767263fcd0073f72c099edaca0607Mike Lockwood                outFileLengthFormat[0] = new File(path).length();
944f6f16614574767263fcd0073f72c099edaca0607Mike Lockwood                outFileLengthFormat[1] = c.getLong(2);
9455367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood                return MtpConstants.RESPONSE_OK;
94659c777a24a2c639dfd84b7bf17e430e6d3424866Mike Lockwood            } else {
9475367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood                return MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE;
948d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            }
949d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        } catch (RemoteException e) {
950d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            Log.e(TAG, "RemoteException in getObjectFilePath", e);
9515367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood            return MtpConstants.RESPONSE_GENERAL_ERROR;
952d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        } finally {
953d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            if (c != null) {
954d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                c.close();
955d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            }
956d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        }
957d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    }
958d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
95959c777a24a2c639dfd84b7bf17e430e6d3424866Mike Lockwood    private int deleteFile(int handle) {
9602837eefc5459427138c080d445bb491c75630163Mike Lockwood        mDatabaseModified = true;
96155f808cff9913a00164120a422af6ca45db5072bMike Lockwood        String path = null;
96255f808cff9913a00164120a422af6ca45db5072bMike Lockwood        int format = 0;
96355f808cff9913a00164120a422af6ca45db5072bMike Lockwood
96455f808cff9913a00164120a422af6ca45db5072bMike Lockwood        Cursor c = null;
965d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        try {
96635654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            c = mMediaProvider.query(mPackageName, mObjectsUri, PATH_FORMAT_PROJECTION,
96775ea64fc54f328d37b115cfb1ded1e45c30380edJeff Brown                            ID_WHERE, new String[] {  Integer.toString(handle) }, null, null);
96855f808cff9913a00164120a422af6ca45db5072bMike Lockwood            if (c != null && c.moveToNext()) {
96955f808cff9913a00164120a422af6ca45db5072bMike Lockwood                // don't convert to media path here, since we will be matching
97055f808cff9913a00164120a422af6ca45db5072bMike Lockwood                // against paths in the database matching /data/media
97155f808cff9913a00164120a422af6ca45db5072bMike Lockwood                path = c.getString(1);
972f6f16614574767263fcd0073f72c099edaca0607Mike Lockwood                format = c.getInt(2);
97355f808cff9913a00164120a422af6ca45db5072bMike Lockwood            } else {
97455f808cff9913a00164120a422af6ca45db5072bMike Lockwood                return MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE;
97555f808cff9913a00164120a422af6ca45db5072bMike Lockwood            }
97655f808cff9913a00164120a422af6ca45db5072bMike Lockwood
97755f808cff9913a00164120a422af6ca45db5072bMike Lockwood            if (path == null || format == 0) {
97855f808cff9913a00164120a422af6ca45db5072bMike Lockwood                return MtpConstants.RESPONSE_GENERAL_ERROR;
97955f808cff9913a00164120a422af6ca45db5072bMike Lockwood            }
98055f808cff9913a00164120a422af6ca45db5072bMike Lockwood
98173e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood            // do not allow deleting any of the special subdirectories
98273e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood            if (isStorageSubDirectory(path)) {
98373e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood                return MtpConstants.RESPONSE_OBJECT_WRITE_PROTECTED;
98473e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood            }
98573e56d935e7c9b8a06e4781c4995e407e118f93dMike Lockwood
98655f808cff9913a00164120a422af6ca45db5072bMike Lockwood            if (format == MtpConstants.FORMAT_ASSOCIATION) {
98755f808cff9913a00164120a422af6ca45db5072bMike Lockwood                // recursive case - delete all children first
98855f808cff9913a00164120a422af6ca45db5072bMike Lockwood                Uri uri = Files.getMtpObjectsUri(mVolumeName);
98935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                int count = mMediaProvider.delete(mPackageName, uri,
9901e855d98aa979b30cee9e096cf6a1cb54df0367bMike Lockwood                    // the 'like' makes it use the index, the 'lower()' makes it correct
9911e855d98aa979b30cee9e096cf6a1cb54df0367bMike Lockwood                    // when the path contains sqlite wildcard characters
9921e855d98aa979b30cee9e096cf6a1cb54df0367bMike Lockwood                    "_data LIKE ?1 AND lower(substr(_data,1,?2))=lower(?3)",
9931e855d98aa979b30cee9e096cf6a1cb54df0367bMike Lockwood                    new String[] { path + "/%",Integer.toString(path.length() + 1), path + "/"});
99455f808cff9913a00164120a422af6ca45db5072bMike Lockwood            }
99555f808cff9913a00164120a422af6ca45db5072bMike Lockwood
99655f808cff9913a00164120a422af6ca45db5072bMike Lockwood            Uri uri = Files.getMtpObjectsUri(mVolumeName, handle);
99735654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            if (mMediaProvider.delete(mPackageName, uri, null, null) > 0) {
998ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen                if (format != MtpConstants.FORMAT_ASSOCIATION
999ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen                        && path.toLowerCase(Locale.US).endsWith("/.nomedia")) {
1000ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen                    try {
1001ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen                        String parentPath = path.substring(0, path.lastIndexOf("/"));
100235654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn                        mMediaProvider.call(mPackageName, MediaStore.UNHIDE_CALL, parentPath, null);
1003ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen                    } catch (RemoteException e) {
1004ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen                        Log.e(TAG, "failed to unhide/rescan for " + path);
1005ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen                    }
1006ca78f3d9aff78c35bc065b0c35a0b3c917f56435Marco Nelissen                }
10075367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood                return MtpConstants.RESPONSE_OK;
100859c777a24a2c639dfd84b7bf17e430e6d3424866Mike Lockwood            } else {
10095367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood                return MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE;
101059c777a24a2c639dfd84b7bf17e430e6d3424866Mike Lockwood            }
1011d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        } catch (RemoteException e) {
1012d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            Log.e(TAG, "RemoteException in deleteFile", e);
10135367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood            return MtpConstants.RESPONSE_GENERAL_ERROR;
101455f808cff9913a00164120a422af6ca45db5072bMike Lockwood        } finally {
101555f808cff9913a00164120a422af6ca45db5072bMike Lockwood            if (c != null) {
101655f808cff9913a00164120a422af6ca45db5072bMike Lockwood                c.close();
101755f808cff9913a00164120a422af6ca45db5072bMike Lockwood            }
1018d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        }
1019d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    }
1020d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
10219a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood    private int[] getObjectReferences(int handle) {
10228490e66f57506d4e4b05e7c987c7ca34295843e6Mike Lockwood        Uri uri = Files.getMtpReferencesUri(mVolumeName, handle);
10239a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood        Cursor c = null;
10249a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood        try {
102535654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            c = mMediaProvider.query(mPackageName, uri, ID_PROJECTION, null, null, null, null);
10269a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            if (c == null) {
10279a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                return null;
10289a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            }
10299a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            int count = c.getCount();
10309a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            if (count > 0) {
10319a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                int[] result = new int[count];
10329a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                for (int i = 0; i < count; i++) {
10339a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                    c.moveToNext();
10349a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                    result[i] = c.getInt(0);
10359a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                }
10369a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                return result;
10379a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            }
10389a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood        } catch (RemoteException e) {
10399a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            Log.e(TAG, "RemoteException in getObjectList", e);
10409a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood        } finally {
10419a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            if (c != null) {
10429a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                c.close();
10439a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            }
10449a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood        }
10459a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood        return null;
10469a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood    }
10479a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood
10489a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood    private int setObjectReferences(int handle, int[] references) {
10492837eefc5459427138c080d445bb491c75630163Mike Lockwood        mDatabaseModified = true;
10508490e66f57506d4e4b05e7c987c7ca34295843e6Mike Lockwood        Uri uri = Files.getMtpReferencesUri(mVolumeName, handle);
10519a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood        int count = references.length;
10529a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood        ContentValues[] valuesList = new ContentValues[count];
10539a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood        for (int i = 0; i < count; i++) {
10549a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            ContentValues values = new ContentValues();
10553b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood            values.put(Files.FileColumns._ID, references[i]);
10569a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            valuesList[i] = values;
10579a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood        }
10589a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood        try {
105935654b61e8fe7bc85afcb076ddbb590d51c5865fDianne Hackborn            if (mMediaProvider.bulkInsert(mPackageName, uri, valuesList) > 0) {
10605367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood                return MtpConstants.RESPONSE_OK;
10619a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            }
10629a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood        } catch (RemoteException e) {
10639a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            Log.e(TAG, "RemoteException in setObjectReferences", e);
10649a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood        }
10655367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood        return MtpConstants.RESPONSE_GENERAL_ERROR;
10669a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood    }
10679a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood
10682837eefc5459427138c080d445bb491c75630163Mike Lockwood    private void sessionStarted() {
10692837eefc5459427138c080d445bb491c75630163Mike Lockwood        mDatabaseModified = false;
10702837eefc5459427138c080d445bb491c75630163Mike Lockwood    }
10712837eefc5459427138c080d445bb491c75630163Mike Lockwood
10722837eefc5459427138c080d445bb491c75630163Mike Lockwood    private void sessionEnded() {
10732837eefc5459427138c080d445bb491c75630163Mike Lockwood        if (mDatabaseModified) {
1074a31560598af25d5116effc2a6af0d9be12a0628dMike Lockwood            mContext.sendBroadcast(new Intent(MediaStore.ACTION_MTP_SESSION_END));
10752837eefc5459427138c080d445bb491c75630163Mike Lockwood            mDatabaseModified = false;
10762837eefc5459427138c080d445bb491c75630163Mike Lockwood        }
10772837eefc5459427138c080d445bb491c75630163Mike Lockwood    }
10782837eefc5459427138c080d445bb491c75630163Mike Lockwood
1079d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    // used by the JNI code
1080e2e59326f13cf291bf5b37989390fd2a55a94f0cAshok Bhat    private long mNativeContext;
1081d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
1082d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private native final void native_setup();
1083d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private native final void native_finalize();
1084d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood}
1085