MtpDatabase.java revision 2b5f9ad1eaf0d6daaca5cf3761434a09309902bb
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
17d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwoodpackage android.media;
18d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
19d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwoodimport android.content.Context;
20d815f79766984fce499e147ecbacc01914683f74Mike Lockwoodimport android.content.ContentValues;
21d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwoodimport android.content.IContentProvider;
222837eefc5459427138c080d445bb491c75630163Mike Lockwoodimport android.content.Intent;
23d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwoodimport android.database.Cursor;
2459e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwoodimport android.database.sqlite.SQLiteDatabase;
25d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwoodimport android.net.Uri;
262b5f9ad1eaf0d6daaca5cf3761434a09309902bbMike Lockwoodimport android.os.Environment;
27d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwoodimport android.os.RemoteException;
289a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwoodimport android.provider.MediaStore.Audio;
293b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwoodimport android.provider.MediaStore.Files;
30ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwoodimport android.provider.MediaStore.Images;
31ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwoodimport android.provider.MediaStore.MediaColumns;
322837eefc5459427138c080d445bb491c75630163Mike Lockwoodimport android.provider.Mtp;
33d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwoodimport android.util.Log;
34d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
355ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwoodimport java.io.File;
365ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood
37d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood/**
38d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood * {@hide}
39d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood */
40d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwoodpublic class MtpDatabase {
41d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
42d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private static final String TAG = "MtpDatabase";
43d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
442837eefc5459427138c080d445bb491c75630163Mike Lockwood    private final Context mContext;
45d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private final IContentProvider mMediaProvider;
46d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private final String mVolumeName;
47d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private final Uri mObjectsUri;
4801788562f26f213f63c14483fd3977e23b8314abMike Lockwood    private final String mMediaStoragePath;
492b5f9ad1eaf0d6daaca5cf3761434a09309902bbMike Lockwood    private final String mExternalStoragePath;
50d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
512837eefc5459427138c080d445bb491c75630163Mike Lockwood    // true if the database has been modified in the current MTP session
522837eefc5459427138c080d445bb491c75630163Mike Lockwood    private boolean mDatabaseModified;
532837eefc5459427138c080d445bb491c75630163Mike Lockwood
5459e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood    // database for writable MTP device properties
5559e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood    private SQLiteDatabase mDevicePropDb;
5659e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood    private static final int DEVICE_PROPERTIES_DATABASE_VERSION = 1;
5759e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood
58b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood    // FIXME - this should be passed in via the constructor
59b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood    private final int mStorageID = 0x00010001;
60b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood
61d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private static final String[] ID_PROJECTION = new String[] {
623b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood            Files.FileColumns._ID, // 0
63d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    };
646a6a3aff17e057eeb1457ac4d04ab4b5e8f53abeMike Lockwood    private static final String[] PATH_PROJECTION = new String[] {
655ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood            Files.FileColumns._ID, // 0
665ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood            Files.FileColumns.DATA, // 1
675ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood    };
68d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private static final String[] PATH_SIZE_PROJECTION = new String[] {
693b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood            Files.FileColumns._ID, // 0
703b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood            Files.FileColumns.DATA, // 1
713b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood            Files.FileColumns.SIZE, // 2
72d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    };
73d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private static final String[] OBJECT_INFO_PROJECTION = new String[] {
743b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood            Files.FileColumns._ID, // 0
753b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood            Files.FileColumns.DATA, // 1
763b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood            Files.FileColumns.FORMAT, // 2
773b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood            Files.FileColumns.PARENT, // 3
783b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood            Files.FileColumns.SIZE, // 4
793b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood            Files.FileColumns.DATE_MODIFIED, // 5
80d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    };
813b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood    private static final String ID_WHERE = Files.FileColumns._ID + "=?";
823b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood    private static final String PARENT_WHERE = Files.FileColumns.PARENT + "=?";
83d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private static final String PARENT_FORMAT_WHERE = PARENT_WHERE + " AND "
843b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood                                            + Files.FileColumns.FORMAT + "=?";
85d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
8659e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood    private static final String[] DEVICE_PROPERTY_PROJECTION = new String[] { "_id", "value" };
8759e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood    private  static final String DEVICE_PROPERTY_WHERE = "code=?";
8859e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood
89d815f79766984fce499e147ecbacc01914683f74Mike Lockwood    private final MediaScanner mMediaScanner;
90d815f79766984fce499e147ecbacc01914683f74Mike Lockwood
91d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    static {
92d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        System.loadLibrary("media_jni");
93d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    }
94d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
9501788562f26f213f63c14483fd3977e23b8314abMike Lockwood    public MtpDatabase(Context context, String volumeName, String storagePath) {
96d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        native_setup();
97d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
982837eefc5459427138c080d445bb491c75630163Mike Lockwood        mContext = context;
99d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        mMediaProvider = context.getContentResolver().acquireProvider("media");
100d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        mVolumeName = volumeName;
10101788562f26f213f63c14483fd3977e23b8314abMike Lockwood        mMediaStoragePath = storagePath;
1022b5f9ad1eaf0d6daaca5cf3761434a09309902bbMike Lockwood        mExternalStoragePath = Environment.getExternalStorageDirectory().getAbsolutePath();
1038490e66f57506d4e4b05e7c987c7ca34295843e6Mike Lockwood        mObjectsUri = Files.getMtpObjectsUri(volumeName);
104d815f79766984fce499e147ecbacc01914683f74Mike Lockwood        mMediaScanner = new MediaScanner(context);
10559e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood        openDevicePropertiesDatabase(context);
106d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    }
107d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
108d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    @Override
109dbead321daf2c16dc74e182bec591b278cfccb2cMike Lockwood    protected void finalize() throws Throwable {
110dbead321daf2c16dc74e182bec591b278cfccb2cMike Lockwood        try {
111dbead321daf2c16dc74e182bec591b278cfccb2cMike Lockwood            native_finalize();
112dbead321daf2c16dc74e182bec591b278cfccb2cMike Lockwood        } finally {
113dbead321daf2c16dc74e182bec591b278cfccb2cMike Lockwood            super.finalize();
114dbead321daf2c16dc74e182bec591b278cfccb2cMike Lockwood        }
115d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    }
116d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
1172b5f9ad1eaf0d6daaca5cf3761434a09309902bbMike Lockwood    private String externalToMediaPath(String path) {
1182b5f9ad1eaf0d6daaca5cf3761434a09309902bbMike Lockwood        // convert external storage path to media path
1192b5f9ad1eaf0d6daaca5cf3761434a09309902bbMike Lockwood        if (path != null && mMediaStoragePath != null
1202b5f9ad1eaf0d6daaca5cf3761434a09309902bbMike Lockwood                && mExternalStoragePath != null
1212b5f9ad1eaf0d6daaca5cf3761434a09309902bbMike Lockwood                && path.startsWith(mExternalStoragePath)) {
1222b5f9ad1eaf0d6daaca5cf3761434a09309902bbMike Lockwood            path = mMediaStoragePath + path.substring(mExternalStoragePath.length());
1232b5f9ad1eaf0d6daaca5cf3761434a09309902bbMike Lockwood        }
1242b5f9ad1eaf0d6daaca5cf3761434a09309902bbMike Lockwood        return path;
1252b5f9ad1eaf0d6daaca5cf3761434a09309902bbMike Lockwood    }
1262b5f9ad1eaf0d6daaca5cf3761434a09309902bbMike Lockwood
12759e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood    private void openDevicePropertiesDatabase(Context context) {
12859e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood        mDevicePropDb = context.openOrCreateDatabase("device-properties", Context.MODE_PRIVATE, null);
12959e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood        int version = mDevicePropDb.getVersion();
13059e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood
13159e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood        // initialize if necessary
13259e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood        if (version != DEVICE_PROPERTIES_DATABASE_VERSION) {
13359e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood            mDevicePropDb.execSQL("CREATE TABLE properties (" +
13459e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                    "_id INTEGER PRIMARY KEY AUTOINCREMENT," +
13559e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                    "code INTEGER UNIQUE ON CONFLICT REPLACE," +
13659e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                    "value TEXT" +
13759e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                    ");");
13859e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood            mDevicePropDb.execSQL("CREATE INDEX property_index ON properties (code);");
13959e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood            mDevicePropDb.setVersion(DEVICE_PROPERTIES_DATABASE_VERSION);
14059e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood        }
14159e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood    }
14259e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood
143d815f79766984fce499e147ecbacc01914683f74Mike Lockwood    private int beginSendObject(String path, int format, int parent,
144d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                         int storage, long size, long modified) {
1452837eefc5459427138c080d445bb491c75630163Mike Lockwood        mDatabaseModified = true;
146d815f79766984fce499e147ecbacc01914683f74Mike Lockwood        ContentValues values = new ContentValues();
1473b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood        values.put(Files.FileColumns.DATA, path);
1483b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood        values.put(Files.FileColumns.FORMAT, format);
1493b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood        values.put(Files.FileColumns.PARENT, parent);
150d815f79766984fce499e147ecbacc01914683f74Mike Lockwood        // storage is ignored for now
1513b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood        values.put(Files.FileColumns.SIZE, size);
1523b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood        values.put(Files.FileColumns.DATE_MODIFIED, modified);
153d815f79766984fce499e147ecbacc01914683f74Mike Lockwood
154d815f79766984fce499e147ecbacc01914683f74Mike Lockwood        try {
155d815f79766984fce499e147ecbacc01914683f74Mike Lockwood            Uri uri = mMediaProvider.insert(mObjectsUri, values);
156d815f79766984fce499e147ecbacc01914683f74Mike Lockwood            if (uri != null) {
157d815f79766984fce499e147ecbacc01914683f74Mike Lockwood                return Integer.parseInt(uri.getPathSegments().get(2));
158d815f79766984fce499e147ecbacc01914683f74Mike Lockwood            } else {
159d815f79766984fce499e147ecbacc01914683f74Mike Lockwood                return -1;
160d815f79766984fce499e147ecbacc01914683f74Mike Lockwood            }
161d815f79766984fce499e147ecbacc01914683f74Mike Lockwood        } catch (RemoteException e) {
162d815f79766984fce499e147ecbacc01914683f74Mike Lockwood            Log.e(TAG, "RemoteException in beginSendObject", e);
163d815f79766984fce499e147ecbacc01914683f74Mike Lockwood            return -1;
164d815f79766984fce499e147ecbacc01914683f74Mike Lockwood        }
165d815f79766984fce499e147ecbacc01914683f74Mike Lockwood    }
166d815f79766984fce499e147ecbacc01914683f74Mike Lockwood
167d815f79766984fce499e147ecbacc01914683f74Mike Lockwood    private void endSendObject(String path, int handle, int format, boolean succeeded) {
168d815f79766984fce499e147ecbacc01914683f74Mike Lockwood        if (succeeded) {
1699a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            // handle abstract playlists separately
1709a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            // they do not exist in the file system so don't use the media scanner here
1715367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood            if (format == MtpConstants.FORMAT_ABSTRACT_AV_PLAYLIST) {
1729a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                // Strip Windows Media Player file extension
1739a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                if (path.endsWith(".pla")) {
1749a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                    path = path.substring(0, path.length() - 4);
1759a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                }
1769a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood
1779a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                // extract name from path
1789a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                String name = path;
1799a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                int lastSlash = name.lastIndexOf('/');
1809a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                if (lastSlash >= 0) {
1819a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                    name = name.substring(lastSlash + 1);
1829a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                }
1839a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood
1849a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                ContentValues values = new ContentValues(1);
1859a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                values.put(Audio.Playlists.DATA, path);
1869a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                values.put(Audio.Playlists.NAME, name);
1879a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                values.put(MediaColumns.MEDIA_SCANNER_NEW_OBJECT_ID, handle);
1889a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                try {
1899a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                    Uri uri = mMediaProvider.insert(Audio.Playlists.EXTERNAL_CONTENT_URI, values);
1909a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                } catch (RemoteException e) {
1919a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                    Log.e(TAG, "RemoteException in endSendObject", e);
1929a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                }
1939a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            } else {
194c37255d5d0fd9e0ec02b0d7cb5c4b235e200d367Mike Lockwood                mMediaScanner.scanMtpFile(path, mVolumeName, handle, format);
1959a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            }
196d815f79766984fce499e147ecbacc01914683f74Mike Lockwood        } else {
197d815f79766984fce499e147ecbacc01914683f74Mike Lockwood            deleteFile(handle);
198d815f79766984fce499e147ecbacc01914683f74Mike Lockwood        }
199d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    }
200d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
201d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private int[] getObjectList(int storageID, int format, int parent) {
202d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        // we can ignore storageID until we support multiple storages
203d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        Log.d(TAG, "getObjectList parent: " + parent);
204d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        Cursor c = null;
205d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        try {
206d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            if (format != 0) {
207d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                c = mMediaProvider.query(mObjectsUri, ID_PROJECTION,
208d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                            PARENT_FORMAT_WHERE,
209d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                            new String[] { Integer.toString(parent), Integer.toString(format) },
210d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                             null);
211d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            } else {
212d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                c = mMediaProvider.query(mObjectsUri, ID_PROJECTION,
213d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                            PARENT_WHERE, new String[] { Integer.toString(parent) }, null);
214d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            }
215d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            if (c == null) {
216d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                Log.d(TAG, "null cursor");
217d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                return null;
218d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            }
219d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            int count = c.getCount();
220d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            if (count > 0) {
221d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                int[] result = new int[count];
222d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                for (int i = 0; i < count; i++) {
223d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                    c.moveToNext();
224d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                    result[i] = c.getInt(0);
225d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                }
226d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                Log.d(TAG, "returning " + result);
227d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                return result;
228d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            }
229d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        } catch (RemoteException e) {
230d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            Log.e(TAG, "RemoteException in getObjectList", e);
231d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        } finally {
232d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            if (c != null) {
233d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                c.close();
234d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            }
235d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        }
236d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        return null;
237d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    }
238d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
2397a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood    private int getNumObjects(int storageID, int format, int parent) {
2407a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood        // we can ignore storageID until we support multiple storages
2417a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood        Log.d(TAG, "getObjectList parent: " + parent);
2427a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood        Cursor c = null;
2437a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood        try {
2447a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood            if (format != 0) {
2457a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood                c = mMediaProvider.query(mObjectsUri, ID_PROJECTION,
2467a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood                            PARENT_FORMAT_WHERE,
2477a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood                            new String[] { Integer.toString(parent), Integer.toString(format) },
2487a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood                             null);
2497a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood            } else {
2507a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood                c = mMediaProvider.query(mObjectsUri, ID_PROJECTION,
2517a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood                            PARENT_WHERE, new String[] { Integer.toString(parent) }, null);
2527a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood            }
2537a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood            if (c != null) {
2547a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood                return c.getCount();
2557a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood            }
2567a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood        } catch (RemoteException e) {
2577a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood            Log.e(TAG, "RemoteException in getNumObjects", e);
2587a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood        } finally {
2597a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood            if (c != null) {
2607a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood                c.close();
2617a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood            }
2627a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood        }
2637a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood        return -1;
2647a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood    }
2657a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood
2664b322ce4fb86b5a7a6e50633a3a9f498ca8d4706Mike Lockwood    private int[] getSupportedPlaybackFormats() {
2674b322ce4fb86b5a7a6e50633a3a9f498ca8d4706Mike Lockwood        return new int[] {
268e521169ff5dc6cbe1762bd7a049d95b56cc657eeMike Lockwood            // allow transfering arbitrary files
269e521169ff5dc6cbe1762bd7a049d95b56cc657eeMike Lockwood            MtpConstants.FORMAT_UNDEFINED,
27012b8a99fc1d4acc427307a4a924bf33745410260Mike Lockwood
271792ec849e5bc27c090c62f578846b888fa43e0d6Mike Lockwood            MtpConstants.FORMAT_ASSOCIATION,
27212b8a99fc1d4acc427307a4a924bf33745410260Mike Lockwood            MtpConstants.FORMAT_TEXT,
27312b8a99fc1d4acc427307a4a924bf33745410260Mike Lockwood            MtpConstants.FORMAT_HTML,
27412b8a99fc1d4acc427307a4a924bf33745410260Mike Lockwood            MtpConstants.FORMAT_WAV,
27512b8a99fc1d4acc427307a4a924bf33745410260Mike Lockwood            MtpConstants.FORMAT_MP3,
27612b8a99fc1d4acc427307a4a924bf33745410260Mike Lockwood            MtpConstants.FORMAT_MPEG,
27712b8a99fc1d4acc427307a4a924bf33745410260Mike Lockwood            MtpConstants.FORMAT_EXIF_JPEG,
27812b8a99fc1d4acc427307a4a924bf33745410260Mike Lockwood            MtpConstants.FORMAT_TIFF_EP,
27912b8a99fc1d4acc427307a4a924bf33745410260Mike Lockwood            MtpConstants.FORMAT_GIF,
28012b8a99fc1d4acc427307a4a924bf33745410260Mike Lockwood            MtpConstants.FORMAT_JFIF,
28112b8a99fc1d4acc427307a4a924bf33745410260Mike Lockwood            MtpConstants.FORMAT_PNG,
28212b8a99fc1d4acc427307a4a924bf33745410260Mike Lockwood            MtpConstants.FORMAT_TIFF,
28312b8a99fc1d4acc427307a4a924bf33745410260Mike Lockwood            MtpConstants.FORMAT_WMA,
28412b8a99fc1d4acc427307a4a924bf33745410260Mike Lockwood            MtpConstants.FORMAT_OGG,
28512b8a99fc1d4acc427307a4a924bf33745410260Mike Lockwood            MtpConstants.FORMAT_AAC,
28612b8a99fc1d4acc427307a4a924bf33745410260Mike Lockwood            MtpConstants.FORMAT_MP4_CONTAINER,
28712b8a99fc1d4acc427307a4a924bf33745410260Mike Lockwood            MtpConstants.FORMAT_MP2,
28812b8a99fc1d4acc427307a4a924bf33745410260Mike Lockwood            MtpConstants.FORMAT_3GP_CONTAINER,
289792ec849e5bc27c090c62f578846b888fa43e0d6Mike Lockwood            MtpConstants.FORMAT_ABSTRACT_AV_PLAYLIST,
29012b8a99fc1d4acc427307a4a924bf33745410260Mike Lockwood            MtpConstants.FORMAT_WPL_PLAYLIST,
29112b8a99fc1d4acc427307a4a924bf33745410260Mike Lockwood            MtpConstants.FORMAT_M3U_PLAYLIST,
29212b8a99fc1d4acc427307a4a924bf33745410260Mike Lockwood            MtpConstants.FORMAT_PLS_PLAYLIST,
29312b8a99fc1d4acc427307a4a924bf33745410260Mike Lockwood            MtpConstants.FORMAT_XML_DOCUMENT,
2944b322ce4fb86b5a7a6e50633a3a9f498ca8d4706Mike Lockwood        };
2954b322ce4fb86b5a7a6e50633a3a9f498ca8d4706Mike Lockwood    }
2964b322ce4fb86b5a7a6e50633a3a9f498ca8d4706Mike Lockwood
2974b322ce4fb86b5a7a6e50633a3a9f498ca8d4706Mike Lockwood    private int[] getSupportedCaptureFormats() {
2984b322ce4fb86b5a7a6e50633a3a9f498ca8d4706Mike Lockwood        // no capture formats yet
2994b322ce4fb86b5a7a6e50633a3a9f498ca8d4706Mike Lockwood        return null;
3004b322ce4fb86b5a7a6e50633a3a9f498ca8d4706Mike Lockwood    }
3014b322ce4fb86b5a7a6e50633a3a9f498ca8d4706Mike Lockwood
302ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood    static final int[] FILE_PROPERTIES = {
303ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            // NOTE must match beginning of AUDIO_PROPERTIES, VIDEO_PROPERTIES
304ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            // and IMAGE_PROPERTIES below
3055367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood            MtpConstants.PROPERTY_STORAGE_ID,
3065367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood            MtpConstants.PROPERTY_OBJECT_FORMAT,
307d3bfecb0c9bdf3651a06e86c7c8607768a29a9aeMike Lockwood            MtpConstants.PROPERTY_PROTECTION_STATUS,
3085367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood            MtpConstants.PROPERTY_OBJECT_SIZE,
3095367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood            MtpConstants.PROPERTY_OBJECT_FILE_NAME,
310d3bfecb0c9bdf3651a06e86c7c8607768a29a9aeMike Lockwood            MtpConstants.PROPERTY_DATE_MODIFIED,
3115367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood            MtpConstants.PROPERTY_PARENT_OBJECT,
312d3bfecb0c9bdf3651a06e86c7c8607768a29a9aeMike Lockwood            MtpConstants.PROPERTY_PERSISTENT_UID,
313d3bfecb0c9bdf3651a06e86c7c8607768a29a9aeMike Lockwood            MtpConstants.PROPERTY_NAME,
314ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_DATE_ADDED,
315ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood    };
316ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood
317ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood    static final int[] AUDIO_PROPERTIES = {
318ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            // NOTE must match FILE_PROPERTIES above
319ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_STORAGE_ID,
320ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_OBJECT_FORMAT,
321ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_PROTECTION_STATUS,
322ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_OBJECT_SIZE,
323ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_OBJECT_FILE_NAME,
324ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_DATE_MODIFIED,
325ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_PARENT_OBJECT,
326ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_PERSISTENT_UID,
327ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_NAME,
328ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_DISPLAY_NAME,
329ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_DATE_ADDED,
330ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood
331ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            // audio specific properties
332ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_ARTIST,
333ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_ALBUM_NAME,
334ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_ALBUM_ARTIST,
335ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_TRACK,
336ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_ORIGINAL_RELEASE_DATE,
337ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_DURATION,
338ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_GENRE,
339ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_COMPOSER,
340ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood    };
341ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood
342ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood    static final int[] VIDEO_PROPERTIES = {
343ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            // NOTE must match FILE_PROPERTIES above
344ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_STORAGE_ID,
345ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_OBJECT_FORMAT,
346ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_PROTECTION_STATUS,
347ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_OBJECT_SIZE,
348ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_OBJECT_FILE_NAME,
349ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_DATE_MODIFIED,
350ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_PARENT_OBJECT,
351ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_PERSISTENT_UID,
352ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_NAME,
353ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_DISPLAY_NAME,
354ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_DATE_ADDED,
355ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood
356ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            // video specific properties
357ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_ARTIST,
358ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_ALBUM_NAME,
359ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_DURATION,
360ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_DESCRIPTION,
361ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood    };
362ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood
363ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood    static final int[] IMAGE_PROPERTIES = {
364ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            // NOTE must match FILE_PROPERTIES above
365ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_STORAGE_ID,
366ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_OBJECT_FORMAT,
367ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_PROTECTION_STATUS,
368ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_OBJECT_SIZE,
369ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_OBJECT_FILE_NAME,
370ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_DATE_MODIFIED,
371ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_PARENT_OBJECT,
372ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_PERSISTENT_UID,
373ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_NAME,
374ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_DISPLAY_NAME,
375ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_DATE_ADDED,
376ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood
377ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            // image specific properties
378ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            MtpConstants.PROPERTY_DESCRIPTION,
379ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood    };
380ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood
381ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood    private int[] getSupportedObjectProperties(int format) {
382ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood        switch (format) {
383ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            case MtpConstants.FORMAT_MP3:
384ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            case MtpConstants.FORMAT_WAV:
385ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            case MtpConstants.FORMAT_WMA:
386ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            case MtpConstants.FORMAT_OGG:
387ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            case MtpConstants.FORMAT_AAC:
388ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                return AUDIO_PROPERTIES;
389ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            case MtpConstants.FORMAT_MPEG:
390ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            case MtpConstants.FORMAT_3GP_CONTAINER:
391ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            case MtpConstants.FORMAT_WMV:
392ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                return VIDEO_PROPERTIES;
393ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            case MtpConstants.FORMAT_EXIF_JPEG:
394ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            case MtpConstants.FORMAT_GIF:
395ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            case MtpConstants.FORMAT_PNG:
396ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            case MtpConstants.FORMAT_BMP:
397ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                return IMAGE_PROPERTIES;
398ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            default:
399ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                return FILE_PROPERTIES;
400ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood        }
4014b322ce4fb86b5a7a6e50633a3a9f498ca8d4706Mike Lockwood    }
4024b322ce4fb86b5a7a6e50633a3a9f498ca8d4706Mike Lockwood
4034b322ce4fb86b5a7a6e50633a3a9f498ca8d4706Mike Lockwood    private int[] getSupportedDeviceProperties() {
40459e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood        return new int[] {
40559e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood            MtpConstants.DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER,
40659e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood            MtpConstants.DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME,
40759e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood        };
4084b322ce4fb86b5a7a6e50633a3a9f498ca8d4706Mike Lockwood    }
4094b322ce4fb86b5a7a6e50633a3a9f498ca8d4706Mike Lockwood
410ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood    private String queryString(int id, String column) {
411ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood        Cursor c = null;
412ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood        try {
413ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            // for now we are only reading properties from the "objects" table
414ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            c = mMediaProvider.query(mObjectsUri,
415ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                            new String [] { Files.FileColumns._ID, column },
416ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                            ID_WHERE, new String[] { Integer.toString(id) }, null);
417ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            if (c != null && c.moveToNext()) {
418ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                return c.getString(1);
419ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            } else {
420ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                return "";
421ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            }
422ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood        } catch (Exception e) {
423ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            return null;
424ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood        } finally {
425ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            if (c != null) {
426ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                c.close();
427ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            }
428ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood        }
429ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood    }
430ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood
431ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood    private String queryGenre(int id) {
432ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood        Cursor c = null;
433ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood        try {
434ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            Uri uri = Audio.Genres.getContentUriForAudioId(mVolumeName, id);
435ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            c = mMediaProvider.query(uri,
436ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                            new String [] { Files.FileColumns._ID, Audio.GenresColumns.NAME },
437ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                            null, null, null);
438ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            if (c != null && c.moveToNext()) {
439ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                return c.getString(1);
440ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            } else {
441ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                return "";
442ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            }
443ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood        } catch (Exception e) {
444ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            Log.e(TAG, "queryGenre exception", e);
445ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            return null;
446ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood        } finally {
447ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            if (c != null) {
448ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                c.close();
449ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            }
450ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood        }
451ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood    }
452ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood
453ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood    private boolean queryInt(int id, String column, long[] outValue) {
454ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood        Cursor c = null;
455ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood        try {
456ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            // for now we are only reading properties from the "objects" table
457ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            c = mMediaProvider.query(mObjectsUri,
458ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                            new String [] { Files.FileColumns._ID, column },
459ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                            ID_WHERE, new String[] { Integer.toString(id) }, null);
460ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            if (c != null && c.moveToNext()) {
461ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                outValue[0] = c.getLong(1);
462ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                return true;
463ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            }
464ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            return false;
465ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood        } catch (Exception e) {
466ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            return false;
467ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood        } finally {
468ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            if (c != null) {
469ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                c.close();
470ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            }
471ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood        }
472ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood    }
473ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood
474ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood    private String nameFromPath(String path) {
475ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood        // extract name from full path
476ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood        int start = 0;
477ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood        int lastSlash = path.lastIndexOf('/');
478ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood        if (lastSlash >= 0) {
479ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            start = lastSlash + 1;
480ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood        }
481ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood        int end = path.length();
482ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood        if (end - start > 255) {
483ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            end = start + 255;
484ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood        }
485ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood        return path.substring(start, end);
486ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood    }
487ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood
4885ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood    private int renameFile(int handle, String newName) {
4895ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood        Cursor c = null;
4905ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood
4915ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood        // first compute current path
4925ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood        String path = null;
4935ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood        String[] whereArgs = new String[] {  Integer.toString(handle) };
4945ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood        try {
4956a6a3aff17e057eeb1457ac4d04ab4b5e8f53abeMike Lockwood            c = mMediaProvider.query(mObjectsUri, PATH_PROJECTION, ID_WHERE, whereArgs, null);
4965ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood            if (c != null && c.moveToNext()) {
4972b5f9ad1eaf0d6daaca5cf3761434a09309902bbMike Lockwood                path = externalToMediaPath(c.getString(1));
4985ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood            }
4995ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood        } catch (RemoteException e) {
5005ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood            Log.e(TAG, "RemoteException in getObjectFilePath", e);
5015ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood            return MtpConstants.RESPONSE_GENERAL_ERROR;
5025ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood        } finally {
5035ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood            if (c != null) {
5045ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood                c.close();
5055ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood            }
5065ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood        }
5075ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood        if (path == null) {
5085ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood            return MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE;
5095ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood        }
5105ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood
5115ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood        // now rename the file.  make sure this succeeds before updating database
5125ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood        File oldFile = new File(path);
5135ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood        int lastSlash = path.lastIndexOf('/');
5145ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood        if (lastSlash <= 1) {
5155ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood            return MtpConstants.RESPONSE_GENERAL_ERROR;
5165ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood        }
5175ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood        String newPath = path.substring(0, lastSlash + 1) + newName;
5185ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood        File newFile = new File(newPath);
5195ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood        boolean success = oldFile.renameTo(newFile);
5205ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood        Log.d(TAG, "renaming "+ path + " to " + newPath + (success ? " succeeded" : " failed"));
5215ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood        if (!success) {
5225ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood            return MtpConstants.RESPONSE_GENERAL_ERROR;
5235ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood        }
5245ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood
5255ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood        // finally update database
5265ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood        ContentValues values = new ContentValues();
5275ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood        values.put(Files.FileColumns.DATA, newPath);
5285ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood        int updated = 0;
5295ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood        try {
5306a6a3aff17e057eeb1457ac4d04ab4b5e8f53abeMike Lockwood            // note - we are relying on a special case in MediaProvider.update() to update
5316a6a3aff17e057eeb1457ac4d04ab4b5e8f53abeMike Lockwood            // the paths for all children in the case where this is a directory.
5325ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood            updated = mMediaProvider.update(mObjectsUri, values, ID_WHERE, whereArgs);
5335ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood        } catch (RemoteException e) {
5345ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood            Log.e(TAG, "RemoteException in mMediaProvider.update", e);
5355ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood        }
5366a6a3aff17e057eeb1457ac4d04ab4b5e8f53abeMike Lockwood        if (updated == 0) {
5375ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood            Log.e(TAG, "Unable to update path for " + path + " to " + newPath);
5385ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood            // this shouldn't happen, but if it does we need to rename the file to its original name
5395ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood            newFile.renameTo(oldFile);
5405ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood            return MtpConstants.RESPONSE_GENERAL_ERROR;
5415ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood        }
5425ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood
5435ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood        return MtpConstants.RESPONSE_OK;
5445ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood    }
5455ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood
546d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private int getObjectProperty(int handle, int property,
547d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                            long[] outIntValue, char[] outStringValue) {
548d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        Log.d(TAG, "getObjectProperty: " + property);
549b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood        String column = null;
550b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood        boolean isString = false;
551b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood
552b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood        switch (property) {
5535367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood            case MtpConstants.PROPERTY_STORAGE_ID:
554b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                outIntValue[0] = mStorageID;
5555367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood                return MtpConstants.RESPONSE_OK;
5565367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood            case MtpConstants.PROPERTY_OBJECT_FORMAT:
5573b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood                column = Files.FileColumns.FORMAT;
558b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                break;
5595367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood            case MtpConstants.PROPERTY_PROTECTION_STATUS:
560828d19dd96b05fa99abdc517701e5366543c324fMike Lockwood                // protection status is always 0
561828d19dd96b05fa99abdc517701e5366543c324fMike Lockwood                outIntValue[0] = 0;
5625367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood                return MtpConstants.RESPONSE_OK;
5635367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood            case MtpConstants.PROPERTY_OBJECT_SIZE:
5643b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood                column = Files.FileColumns.SIZE;
565b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                break;
5665367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood            case MtpConstants.PROPERTY_OBJECT_FILE_NAME:
567ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                // special case - need to extract file name from full path
568ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                String value = queryString(handle, Files.FileColumns.DATA);
569ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                if (value != null) {
570ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                    value = nameFromPath(value);
571ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                    value.getChars(0, value.length(), outStringValue, 0);
572ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                    outStringValue[value.length()] = 0;
573ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                    return MtpConstants.RESPONSE_OK;
574ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                } else {
575ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                    return MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE;
576ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                }
577ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            case MtpConstants.PROPERTY_NAME:
578ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                // first try title
579ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                String name = queryString(handle, MediaColumns.TITLE);
580ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                // then try name
581ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                if (name == null) {
582ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                    name = queryString(handle, Audio.PlaylistsColumns.NAME);
583ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                }
584ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                // if title and name fail, extract name from full path
585ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                if (name == null) {
586ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                    name = queryString(handle, Files.FileColumns.DATA);
587ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                    if (name != null) {
588ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                        name = nameFromPath(name);
589ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                    }
590ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                }
591ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                if (name != null) {
592ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                    name.getChars(0, name.length(), outStringValue, 0);
593ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                    outStringValue[name.length()] = 0;
594ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                    return MtpConstants.RESPONSE_OK;
595ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                } else {
596ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                    return MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE;
597ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                }
5985367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood            case MtpConstants.PROPERTY_DATE_MODIFIED:
5993b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood                column = Files.FileColumns.DATE_MODIFIED;
600b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                break;
601ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            case MtpConstants.PROPERTY_DATE_ADDED:
602ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                column = Files.FileColumns.DATE_ADDED;
603ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                break;
604ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            case MtpConstants.PROPERTY_ORIGINAL_RELEASE_DATE:
605ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                column = Audio.AudioColumns.YEAR;
606ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                break;
6075367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood            case MtpConstants.PROPERTY_PARENT_OBJECT:
6083b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood                column = Files.FileColumns.PARENT;
609b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                break;
6105367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood            case MtpConstants.PROPERTY_PERSISTENT_UID:
611828d19dd96b05fa99abdc517701e5366543c324fMike Lockwood                // PUID is concatenation of storageID and object handle
612828d19dd96b05fa99abdc517701e5366543c324fMike Lockwood                long puid = mStorageID;
613828d19dd96b05fa99abdc517701e5366543c324fMike Lockwood                puid <<= 32;
614828d19dd96b05fa99abdc517701e5366543c324fMike Lockwood                puid += handle;
615828d19dd96b05fa99abdc517701e5366543c324fMike Lockwood                outIntValue[0] = puid;
6165367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood                return MtpConstants.RESPONSE_OK;
617ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            case MtpConstants.PROPERTY_DURATION:
618ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                column = Audio.AudioColumns.DURATION;
619ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                break;
620ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            case MtpConstants.PROPERTY_TRACK:
621ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                if (queryInt(handle, Audio.AudioColumns.TRACK, outIntValue)) {
622ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                    // track is stored in lower 3 decimal digits
623ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                    outIntValue[0] %= 1000;
624ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                    return MtpConstants.RESPONSE_OK;
625ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                } else {
626ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                    return MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE;
627ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                }
628ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            case MtpConstants.PROPERTY_DISPLAY_NAME:
629ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                column = MediaColumns.DISPLAY_NAME;
630ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                isString = true;
631ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                break;
632ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            case MtpConstants.PROPERTY_ARTIST:
633ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                column = Audio.AudioColumns.ARTIST;
634ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                isString = true;
635ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                break;
636ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            case MtpConstants.PROPERTY_ALBUM_NAME:
637ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                column = Audio.AudioColumns.ALBUM;
638ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                isString = true;
639ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                break;
640ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            case MtpConstants.PROPERTY_ALBUM_ARTIST:
641ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                column = Audio.AudioColumns.ALBUM_ARTIST;
642ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                isString = true;
643ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                break;
644ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            case MtpConstants.PROPERTY_GENRE:
645ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                String genre = queryGenre(handle);
646ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                if (genre != null) {
647ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                    genre.getChars(0, genre.length(), outStringValue, 0);
648ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                    outStringValue[genre.length()] = 0;
649ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                    return MtpConstants.RESPONSE_OK;
650ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                } else {
651ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                    return MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE;
652ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                }
653ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            case MtpConstants.PROPERTY_COMPOSER:
654ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                column = Audio.AudioColumns.COMPOSER;
655ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                isString = true;
656ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                break;
657ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            case MtpConstants.PROPERTY_DESCRIPTION:
658ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                column = Images.ImageColumns.DESCRIPTION;
659ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                isString = true;
660ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                break;
661b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood            default:
6625367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood                return MtpConstants.RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
663b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood        }
664b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood
665ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood        if (isString) {
666ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            String value = queryString(handle, column);
667ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            if (value != null) {
668ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                value.getChars(0, value.length(), outStringValue, 0);
669ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                outStringValue[value.length()] = 0;
6705367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood                return MtpConstants.RESPONSE_OK;
671b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood            }
672ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood        } else {
673ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood            if (queryInt(handle, column, outIntValue)) {
674ae078f7dacdc719d045c2d19bbce019599fec64eMike Lockwood                return MtpConstants.RESPONSE_OK;
675b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood            }
676b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood        }
677b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood        // query failed if we get here
6785367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood        return MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE;
679d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    }
680d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
68159e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood    private int setObjectProperty(int handle, int property,
68259e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                            long intValue, String stringValue) {
68359e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood        Log.d(TAG, "setObjectProperty: " + property);
6845ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood
6855ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood        switch (property) {
6865ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood            case MtpConstants.PROPERTY_OBJECT_FILE_NAME:
6875ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood                return renameFile(handle, stringValue);
6885ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood
6895ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood            default:
6905ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood                return MtpConstants.RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
6915ebac83e20dadf10bd4a0cee4ddf69d0ec049f98Mike Lockwood        }
69259e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood    }
69359e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood
69459e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood    private int getDeviceProperty(int property, long[] outIntValue, char[] outStringValue) {
69559e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood        Log.d(TAG, "getDeviceProperty: " + property);
69659e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood
69759e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood        switch (property) {
69859e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood            case MtpConstants.DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER:
69959e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood            case MtpConstants.DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME:
70059e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                // writable string properties kept in our device property database
70159e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                Cursor c = null;
70259e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                try {
70359e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                    c = mDevicePropDb.query("properties", DEVICE_PROPERTY_PROJECTION,
70459e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                        DEVICE_PROPERTY_WHERE, new String[] {  Integer.toString(property) },
70559e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                        null, null, null);
70659e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood
70759e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                    if (c != null && c.moveToNext()) {
70859e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                        String value = c.getString(1);
70959e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                        int length = value.length();
71059e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                        if (length > 255) {
71159e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                            length = 255;
71259e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                        }
71359e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                        value.getChars(0, length, outStringValue, 0);
71459e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                        outStringValue[length] = 0;
71559e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                    } else {
71659e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                        outStringValue[0] = 0;
71759e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                    }
71859e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                    return MtpConstants.RESPONSE_OK;
71959e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                } finally {
72059e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                    if (c != null) {
72159e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                        c.close();
72259e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                    }
72359e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                }
72459e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood        }
72559e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood
72659e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood        return MtpConstants.RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
72759e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood    }
72859e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood
72959e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood    private int setDeviceProperty(int property, long intValue, String stringValue) {
73059e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood        Log.d(TAG, "setDeviceProperty: " + property + " : " + stringValue);
73159e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood
73259e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood        switch (property) {
73359e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood            case MtpConstants.DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER:
73459e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood            case MtpConstants.DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME:
73559e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                // writable string properties kept in our device property database
73659e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                try {
73759e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                    ContentValues values = new ContentValues();
73859e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                    values.put("code", property);
73959e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                    values.put("value", stringValue);
74059e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                    mDevicePropDb.insert("properties", "code", values);
74159e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                    return MtpConstants.RESPONSE_OK;
74259e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                } catch (Exception e) {
74359e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                    return MtpConstants.RESPONSE_GENERAL_ERROR;
74459e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                }
74559e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood        }
74659e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood
74759e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood        return MtpConstants.RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
74859e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood    }
74959e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood
750d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private boolean getObjectInfo(int handle, int[] outStorageFormatParent,
751d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                        char[] outName, long[] outSizeModified) {
752d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        Log.d(TAG, "getObjectInfo: " + handle);
753d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        Cursor c = null;
754d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        try {
755d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            c = mMediaProvider.query(mObjectsUri, OBJECT_INFO_PROJECTION,
756d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                            ID_WHERE, new String[] {  Integer.toString(handle) }, null);
757d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            if (c != null && c.moveToNext()) {
758b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                outStorageFormatParent[0] = mStorageID;
759d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                outStorageFormatParent[1] = c.getInt(2);
760d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                outStorageFormatParent[2] = c.getInt(3);
761d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
762d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                // extract name from path
763d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                String path = c.getString(1);
764d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                int lastSlash = path.lastIndexOf('/');
765d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                int start = (lastSlash >= 0 ? lastSlash + 1 : 0);
766d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                int end = path.length();
767d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                if (end - start > 255) {
768d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                    end = start + 255;
769d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                }
770d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                path.getChars(start, end, outName, 0);
771d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                outName[end - start] = 0;
772d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
773d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                outSizeModified[0] = c.getLong(4);
774d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                outSizeModified[1] = c.getLong(5);
775d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                return true;
776d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            }
777d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        } catch (RemoteException e) {
7782b5f9ad1eaf0d6daaca5cf3761434a09309902bbMike Lockwood            Log.e(TAG, "RemoteException in getObjectInfo", e);
779d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        } finally {
780d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            if (c != null) {
781d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                c.close();
782d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            }
783d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        }
784d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        return false;
785d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    }
786d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
78759c777a24a2c639dfd84b7bf17e430e6d3424866Mike Lockwood    private int getObjectFilePath(int handle, char[] outFilePath, long[] outFileLength) {
788d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        Log.d(TAG, "getObjectFilePath: " + handle);
78901788562f26f213f63c14483fd3977e23b8314abMike Lockwood        if (handle == 0) {
79001788562f26f213f63c14483fd3977e23b8314abMike Lockwood            // special case root directory
79101788562f26f213f63c14483fd3977e23b8314abMike Lockwood            mMediaStoragePath.getChars(0, mMediaStoragePath.length(), outFilePath, 0);
79201788562f26f213f63c14483fd3977e23b8314abMike Lockwood            outFilePath[mMediaStoragePath.length()] = 0;
79301788562f26f213f63c14483fd3977e23b8314abMike Lockwood            outFileLength[0] = 0;
79401788562f26f213f63c14483fd3977e23b8314abMike Lockwood            return MtpConstants.RESPONSE_OK;
79501788562f26f213f63c14483fd3977e23b8314abMike Lockwood        }
796d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        Cursor c = null;
797d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        try {
798d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            c = mMediaProvider.query(mObjectsUri, PATH_SIZE_PROJECTION,
799d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                            ID_WHERE, new String[] {  Integer.toString(handle) }, null);
800d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            if (c != null && c.moveToNext()) {
8012b5f9ad1eaf0d6daaca5cf3761434a09309902bbMike Lockwood                String path = externalToMediaPath(c.getString(1));
802d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                path.getChars(0, path.length(), outFilePath, 0);
803d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                outFilePath[path.length()] = 0;
804d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                outFileLength[0] = c.getLong(2);
8055367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood                return MtpConstants.RESPONSE_OK;
80659c777a24a2c639dfd84b7bf17e430e6d3424866Mike Lockwood            } else {
8075367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood                return MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE;
808d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            }
809d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        } catch (RemoteException e) {
810d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            Log.e(TAG, "RemoteException in getObjectFilePath", e);
8115367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood            return MtpConstants.RESPONSE_GENERAL_ERROR;
812d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        } finally {
813d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            if (c != null) {
814d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                c.close();
815d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            }
816d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        }
817d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    }
818d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
819ccb6e961941c607208ed9ac44db2dc9a9649b218Mike Lockwood    private int deleteRecursive(int handle) throws RemoteException {
820ccb6e961941c607208ed9ac44db2dc9a9649b218Mike Lockwood        int[] children = getObjectList(0 /* storageID */, 0 /* format */, handle);
821ccb6e961941c607208ed9ac44db2dc9a9649b218Mike Lockwood        Uri uri = Files.getMtpObjectsUri(mVolumeName, handle);
822ccb6e961941c607208ed9ac44db2dc9a9649b218Mike Lockwood        // delete parent first, to avoid potential infinite recursion
823ccb6e961941c607208ed9ac44db2dc9a9649b218Mike Lockwood        int count = mMediaProvider.delete(uri, null, null);
824ccb6e961941c607208ed9ac44db2dc9a9649b218Mike Lockwood        if (count == 1) {
825ccb6e961941c607208ed9ac44db2dc9a9649b218Mike Lockwood            if (children != null) {
826ccb6e961941c607208ed9ac44db2dc9a9649b218Mike Lockwood                for (int i = 0; i < children.length; i++) {
827ccb6e961941c607208ed9ac44db2dc9a9649b218Mike Lockwood                    count += deleteRecursive(children[i]);
828ccb6e961941c607208ed9ac44db2dc9a9649b218Mike Lockwood                }
829ccb6e961941c607208ed9ac44db2dc9a9649b218Mike Lockwood            }
830ccb6e961941c607208ed9ac44db2dc9a9649b218Mike Lockwood        }
831ccb6e961941c607208ed9ac44db2dc9a9649b218Mike Lockwood        return count;
832ccb6e961941c607208ed9ac44db2dc9a9649b218Mike Lockwood    }
833ccb6e961941c607208ed9ac44db2dc9a9649b218Mike Lockwood
83459c777a24a2c639dfd84b7bf17e430e6d3424866Mike Lockwood    private int deleteFile(int handle) {
835d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        Log.d(TAG, "deleteFile: " + handle);
8362837eefc5459427138c080d445bb491c75630163Mike Lockwood        mDatabaseModified = true;
837d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        try {
838ccb6e961941c607208ed9ac44db2dc9a9649b218Mike Lockwood            if (deleteRecursive(handle) > 0) {
8395367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood                return MtpConstants.RESPONSE_OK;
84059c777a24a2c639dfd84b7bf17e430e6d3424866Mike Lockwood            } else {
8415367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood                return MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE;
84259c777a24a2c639dfd84b7bf17e430e6d3424866Mike Lockwood            }
843d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        } catch (RemoteException e) {
844d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            Log.e(TAG, "RemoteException in deleteFile", e);
8455367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood            return MtpConstants.RESPONSE_GENERAL_ERROR;
846d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        }
847d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    }
848d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
8499a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood    private int[] getObjectReferences(int handle) {
8509a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood        Log.d(TAG, "getObjectReferences for: " + handle);
8518490e66f57506d4e4b05e7c987c7ca34295843e6Mike Lockwood        Uri uri = Files.getMtpReferencesUri(mVolumeName, handle);
8529a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood        Cursor c = null;
8539a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood        try {
8549a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            c = mMediaProvider.query(uri, ID_PROJECTION, null, null, null);
8559a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            if (c == null) {
8569a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                return null;
8579a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            }
8589a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            int count = c.getCount();
8599a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            if (count > 0) {
8609a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                int[] result = new int[count];
8619a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                for (int i = 0; i < count; i++) {
8629a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                    c.moveToNext();
8639a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                    result[i] = c.getInt(0);
8649a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                }
8659a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                return result;
8669a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            }
8679a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood        } catch (RemoteException e) {
8689a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            Log.e(TAG, "RemoteException in getObjectList", e);
8699a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood        } finally {
8709a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            if (c != null) {
8719a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                c.close();
8729a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            }
8739a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood        }
8749a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood        return null;
8759a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood    }
8769a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood
8779a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood    private int setObjectReferences(int handle, int[] references) {
8782837eefc5459427138c080d445bb491c75630163Mike Lockwood        mDatabaseModified = true;
8798490e66f57506d4e4b05e7c987c7ca34295843e6Mike Lockwood        Uri uri = Files.getMtpReferencesUri(mVolumeName, handle);
8809a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood        int count = references.length;
8819a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood        ContentValues[] valuesList = new ContentValues[count];
8829a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood        for (int i = 0; i < count; i++) {
8839a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            ContentValues values = new ContentValues();
8843b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood            values.put(Files.FileColumns._ID, references[i]);
8859a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            valuesList[i] = values;
8869a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood        }
8879a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood        try {
8889a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            if (count == mMediaProvider.bulkInsert(uri, valuesList)) {
8895367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood                return MtpConstants.RESPONSE_OK;
8909a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            }
8919a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood        } catch (RemoteException e) {
8929a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            Log.e(TAG, "RemoteException in setObjectReferences", e);
8939a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood        }
8945367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood        return MtpConstants.RESPONSE_GENERAL_ERROR;
8959a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood    }
8969a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood
8972837eefc5459427138c080d445bb491c75630163Mike Lockwood    private void sessionStarted() {
8982837eefc5459427138c080d445bb491c75630163Mike Lockwood        Log.d(TAG, "sessionStarted");
8992837eefc5459427138c080d445bb491c75630163Mike Lockwood        mDatabaseModified = false;
9002837eefc5459427138c080d445bb491c75630163Mike Lockwood    }
9012837eefc5459427138c080d445bb491c75630163Mike Lockwood
9022837eefc5459427138c080d445bb491c75630163Mike Lockwood    private void sessionEnded() {
9032837eefc5459427138c080d445bb491c75630163Mike Lockwood        Log.d(TAG, "sessionEnded");
9042837eefc5459427138c080d445bb491c75630163Mike Lockwood        if (mDatabaseModified) {
9052837eefc5459427138c080d445bb491c75630163Mike Lockwood            Log.d(TAG, "sending ACTION_MTP_SESSION_END");
9062837eefc5459427138c080d445bb491c75630163Mike Lockwood            mContext.sendBroadcast(new Intent(Mtp.ACTION_MTP_SESSION_END));
9072837eefc5459427138c080d445bb491c75630163Mike Lockwood            mDatabaseModified = false;
9082837eefc5459427138c080d445bb491c75630163Mike Lockwood        }
9092837eefc5459427138c080d445bb491c75630163Mike Lockwood    }
9102837eefc5459427138c080d445bb491c75630163Mike Lockwood
911d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    // used by the JNI code
912d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private int mNativeContext;
913d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
914d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private native final void native_setup();
915d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private native final void native_finalize();
916d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood}
917