MtpDatabase.java revision e521169ff5dc6cbe1762bd7a049d95b56cc657ee
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;
26d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwoodimport android.os.RemoteException;
279a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwoodimport android.provider.MediaStore.Audio;
289a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwoodimport android.provider.MediaStore.MediaColumns;
293b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwoodimport android.provider.MediaStore.Files;
302837eefc5459427138c080d445bb491c75630163Mike Lockwoodimport android.provider.Mtp;
31d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwoodimport android.util.Log;
32d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
33d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood/**
34d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood * {@hide}
35d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood */
36d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwoodpublic class MtpDatabase {
37d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
38d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private static final String TAG = "MtpDatabase";
39d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
402837eefc5459427138c080d445bb491c75630163Mike Lockwood    private final Context mContext;
41d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private final IContentProvider mMediaProvider;
42d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private final String mVolumeName;
43d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private final Uri mObjectsUri;
44d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
452837eefc5459427138c080d445bb491c75630163Mike Lockwood    // true if the database has been modified in the current MTP session
462837eefc5459427138c080d445bb491c75630163Mike Lockwood    private boolean mDatabaseModified;
472837eefc5459427138c080d445bb491c75630163Mike Lockwood
4859e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood    // database for writable MTP device properties
4959e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood    private SQLiteDatabase mDevicePropDb;
5059e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood    private static final int DEVICE_PROPERTIES_DATABASE_VERSION = 1;
5159e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood
52b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood    // FIXME - this should be passed in via the constructor
53b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood    private final int mStorageID = 0x00010001;
54b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood
55d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private static final String[] ID_PROJECTION = new String[] {
563b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood            Files.FileColumns._ID, // 0
57d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    };
58d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private static final String[] PATH_SIZE_PROJECTION = new String[] {
593b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood            Files.FileColumns._ID, // 0
603b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood            Files.FileColumns.DATA, // 1
613b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood            Files.FileColumns.SIZE, // 2
62d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    };
63d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private static final String[] OBJECT_INFO_PROJECTION = new String[] {
643b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood            Files.FileColumns._ID, // 0
653b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood            Files.FileColumns.DATA, // 1
663b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood            Files.FileColumns.FORMAT, // 2
673b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood            Files.FileColumns.PARENT, // 3
683b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood            Files.FileColumns.SIZE, // 4
693b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood            Files.FileColumns.DATE_MODIFIED, // 5
70d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    };
713b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood    private static final String ID_WHERE = Files.FileColumns._ID + "=?";
723b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood    private static final String PATH_WHERE = Files.FileColumns.DATA + "=?";
733b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood    private static final String PARENT_WHERE = Files.FileColumns.PARENT + "=?";
74d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private static final String PARENT_FORMAT_WHERE = PARENT_WHERE + " AND "
753b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood                                            + Files.FileColumns.FORMAT + "=?";
76d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
7759e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood    private static final String[] DEVICE_PROPERTY_PROJECTION = new String[] { "_id", "value" };
7859e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood    private  static final String DEVICE_PROPERTY_WHERE = "code=?";
7959e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood
80d815f79766984fce499e147ecbacc01914683f74Mike Lockwood    private final MediaScanner mMediaScanner;
81d815f79766984fce499e147ecbacc01914683f74Mike Lockwood
82d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    static {
83d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        System.loadLibrary("media_jni");
84d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    }
85d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
86d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    public MtpDatabase(Context context, String volumeName) {
87d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        native_setup();
88d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
892837eefc5459427138c080d445bb491c75630163Mike Lockwood        mContext = context;
90d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        mMediaProvider = context.getContentResolver().acquireProvider("media");
91d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        mVolumeName = volumeName;
923b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood        mObjectsUri = Files.getContentUri(volumeName);
93d815f79766984fce499e147ecbacc01914683f74Mike Lockwood        mMediaScanner = new MediaScanner(context);
9459e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood        openDevicePropertiesDatabase(context);
95d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    }
96d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
97d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    @Override
98dbead321daf2c16dc74e182bec591b278cfccb2cMike Lockwood    protected void finalize() throws Throwable {
99dbead321daf2c16dc74e182bec591b278cfccb2cMike Lockwood        try {
100dbead321daf2c16dc74e182bec591b278cfccb2cMike Lockwood            native_finalize();
101dbead321daf2c16dc74e182bec591b278cfccb2cMike Lockwood        } finally {
102dbead321daf2c16dc74e182bec591b278cfccb2cMike Lockwood            super.finalize();
103dbead321daf2c16dc74e182bec591b278cfccb2cMike Lockwood        }
104d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    }
105d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
10659e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood    private void openDevicePropertiesDatabase(Context context) {
10759e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood        mDevicePropDb = context.openOrCreateDatabase("device-properties", Context.MODE_PRIVATE, null);
10859e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood        int version = mDevicePropDb.getVersion();
10959e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood
11059e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood        // initialize if necessary
11159e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood        if (version != DEVICE_PROPERTIES_DATABASE_VERSION) {
11259e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood            mDevicePropDb.execSQL("CREATE TABLE properties (" +
11359e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                    "_id INTEGER PRIMARY KEY AUTOINCREMENT," +
11459e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                    "code INTEGER UNIQUE ON CONFLICT REPLACE," +
11559e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                    "value TEXT" +
11659e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                    ");");
11759e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood            mDevicePropDb.execSQL("CREATE INDEX property_index ON properties (code);");
11859e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood            mDevicePropDb.setVersion(DEVICE_PROPERTIES_DATABASE_VERSION);
11959e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood        }
12059e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood    }
12159e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood
122d815f79766984fce499e147ecbacc01914683f74Mike Lockwood    private int beginSendObject(String path, int format, int parent,
123d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                         int storage, long size, long modified) {
1242837eefc5459427138c080d445bb491c75630163Mike Lockwood        mDatabaseModified = true;
125d815f79766984fce499e147ecbacc01914683f74Mike Lockwood        ContentValues values = new ContentValues();
1263b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood        values.put(Files.FileColumns.DATA, path);
1273b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood        values.put(Files.FileColumns.FORMAT, format);
1283b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood        values.put(Files.FileColumns.PARENT, parent);
129d815f79766984fce499e147ecbacc01914683f74Mike Lockwood        // storage is ignored for now
1303b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood        values.put(Files.FileColumns.SIZE, size);
1313b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood        values.put(Files.FileColumns.DATE_MODIFIED, modified);
132d815f79766984fce499e147ecbacc01914683f74Mike Lockwood
133d815f79766984fce499e147ecbacc01914683f74Mike Lockwood        try {
134d815f79766984fce499e147ecbacc01914683f74Mike Lockwood            Uri uri = mMediaProvider.insert(mObjectsUri, values);
135d815f79766984fce499e147ecbacc01914683f74Mike Lockwood            if (uri != null) {
136d815f79766984fce499e147ecbacc01914683f74Mike Lockwood                return Integer.parseInt(uri.getPathSegments().get(2));
137d815f79766984fce499e147ecbacc01914683f74Mike Lockwood            } else {
138d815f79766984fce499e147ecbacc01914683f74Mike Lockwood                return -1;
139d815f79766984fce499e147ecbacc01914683f74Mike Lockwood            }
140d815f79766984fce499e147ecbacc01914683f74Mike Lockwood        } catch (RemoteException e) {
141d815f79766984fce499e147ecbacc01914683f74Mike Lockwood            Log.e(TAG, "RemoteException in beginSendObject", e);
142d815f79766984fce499e147ecbacc01914683f74Mike Lockwood            return -1;
143d815f79766984fce499e147ecbacc01914683f74Mike Lockwood        }
144d815f79766984fce499e147ecbacc01914683f74Mike Lockwood    }
145d815f79766984fce499e147ecbacc01914683f74Mike Lockwood
146d815f79766984fce499e147ecbacc01914683f74Mike Lockwood    private void endSendObject(String path, int handle, int format, boolean succeeded) {
147d815f79766984fce499e147ecbacc01914683f74Mike Lockwood        if (succeeded) {
1489a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            // handle abstract playlists separately
1499a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            // they do not exist in the file system so don't use the media scanner here
1505367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood            if (format == MtpConstants.FORMAT_ABSTRACT_AV_PLAYLIST) {
1519a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                // Strip Windows Media Player file extension
1529a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                if (path.endsWith(".pla")) {
1539a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                    path = path.substring(0, path.length() - 4);
1549a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                }
1559a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood
1569a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                // extract name from path
1579a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                String name = path;
1589a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                int lastSlash = name.lastIndexOf('/');
1599a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                if (lastSlash >= 0) {
1609a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                    name = name.substring(lastSlash + 1);
1619a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                }
1629a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood
1639a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                ContentValues values = new ContentValues(1);
1649a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                values.put(Audio.Playlists.DATA, path);
1659a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                values.put(Audio.Playlists.NAME, name);
1669a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                values.put(MediaColumns.MEDIA_SCANNER_NEW_OBJECT_ID, handle);
1679a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                try {
1689a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                    Uri uri = mMediaProvider.insert(Audio.Playlists.EXTERNAL_CONTENT_URI, values);
1699a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                } catch (RemoteException e) {
1709a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                    Log.e(TAG, "RemoteException in endSendObject", e);
1719a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                }
1729a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            } else {
1739a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                Uri uri = mMediaScanner.scanMtpFile(path, mVolumeName, handle, format);
1749a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            }
175d815f79766984fce499e147ecbacc01914683f74Mike Lockwood        } else {
176d815f79766984fce499e147ecbacc01914683f74Mike Lockwood            deleteFile(handle);
177d815f79766984fce499e147ecbacc01914683f74Mike Lockwood        }
178d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    }
179d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
180d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private int[] getObjectList(int storageID, int format, int parent) {
181d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        // we can ignore storageID until we support multiple storages
182d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        Log.d(TAG, "getObjectList parent: " + parent);
183d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        Cursor c = null;
184d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        try {
185d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            if (format != 0) {
186d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                c = mMediaProvider.query(mObjectsUri, ID_PROJECTION,
187d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                            PARENT_FORMAT_WHERE,
188d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                            new String[] { Integer.toString(parent), Integer.toString(format) },
189d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                             null);
190d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            } else {
191d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                c = mMediaProvider.query(mObjectsUri, ID_PROJECTION,
192d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                            PARENT_WHERE, new String[] { Integer.toString(parent) }, null);
193d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            }
194d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            if (c == null) {
195d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                Log.d(TAG, "null cursor");
196d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                return null;
197d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            }
198d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            int count = c.getCount();
199d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            if (count > 0) {
200d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                int[] result = new int[count];
201d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                for (int i = 0; i < count; i++) {
202d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                    c.moveToNext();
203d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                    result[i] = c.getInt(0);
204d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                }
205d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                Log.d(TAG, "returning " + result);
206d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                return result;
207d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            }
208d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        } catch (RemoteException e) {
209d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            Log.e(TAG, "RemoteException in getObjectList", e);
210d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        } finally {
211d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            if (c != null) {
212d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                c.close();
213d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            }
214d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        }
215d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        return null;
216d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    }
217d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
2187a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood    private int getNumObjects(int storageID, int format, int parent) {
2197a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood        // we can ignore storageID until we support multiple storages
2207a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood        Log.d(TAG, "getObjectList parent: " + parent);
2217a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood        Cursor c = null;
2227a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood        try {
2237a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood            if (format != 0) {
2247a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood                c = mMediaProvider.query(mObjectsUri, ID_PROJECTION,
2257a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood                            PARENT_FORMAT_WHERE,
2267a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood                            new String[] { Integer.toString(parent), Integer.toString(format) },
2277a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood                             null);
2287a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood            } else {
2297a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood                c = mMediaProvider.query(mObjectsUri, ID_PROJECTION,
2307a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood                            PARENT_WHERE, new String[] { Integer.toString(parent) }, null);
2317a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood            }
2327a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood            if (c != null) {
2337a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood                return c.getCount();
2347a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood            }
2357a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood        } catch (RemoteException e) {
2367a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood            Log.e(TAG, "RemoteException in getNumObjects", e);
2377a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood        } finally {
2387a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood            if (c != null) {
2397a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood                c.close();
2407a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood            }
2417a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood        }
2427a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood        return -1;
2437a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood    }
2447a047c89862febf63ce1bb5873179c7a2ff8d9d3Mike Lockwood
2454b322ce4fb86b5a7a6e50633a3a9f498ca8d4706Mike Lockwood    private int[] getSupportedPlaybackFormats() {
2464b322ce4fb86b5a7a6e50633a3a9f498ca8d4706Mike Lockwood        return new int[] {
247e521169ff5dc6cbe1762bd7a049d95b56cc657eeMike Lockwood            // allow transfering arbitrary files
248e521169ff5dc6cbe1762bd7a049d95b56cc657eeMike Lockwood            MtpConstants.FORMAT_UNDEFINED,
2494b322ce4fb86b5a7a6e50633a3a9f498ca8d4706Mike Lockwood        };
2504b322ce4fb86b5a7a6e50633a3a9f498ca8d4706Mike Lockwood    }
2514b322ce4fb86b5a7a6e50633a3a9f498ca8d4706Mike Lockwood
2524b322ce4fb86b5a7a6e50633a3a9f498ca8d4706Mike Lockwood    private int[] getSupportedCaptureFormats() {
2534b322ce4fb86b5a7a6e50633a3a9f498ca8d4706Mike Lockwood        // no capture formats yet
2544b322ce4fb86b5a7a6e50633a3a9f498ca8d4706Mike Lockwood        return null;
2554b322ce4fb86b5a7a6e50633a3a9f498ca8d4706Mike Lockwood    }
2564b322ce4fb86b5a7a6e50633a3a9f498ca8d4706Mike Lockwood
2574b322ce4fb86b5a7a6e50633a3a9f498ca8d4706Mike Lockwood    private int[] getSupportedObjectProperties(int handle) {
2584b322ce4fb86b5a7a6e50633a3a9f498ca8d4706Mike Lockwood        return new int[] {
2595367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood            MtpConstants.PROPERTY_STORAGE_ID,
2605367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood            MtpConstants.PROPERTY_OBJECT_FORMAT,
2615367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood            MtpConstants.PROPERTY_OBJECT_SIZE,
2625367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood            MtpConstants.PROPERTY_OBJECT_FILE_NAME,
2635367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood            MtpConstants.PROPERTY_PARENT_OBJECT,
2644b322ce4fb86b5a7a6e50633a3a9f498ca8d4706Mike Lockwood        };
2654b322ce4fb86b5a7a6e50633a3a9f498ca8d4706Mike Lockwood    }
2664b322ce4fb86b5a7a6e50633a3a9f498ca8d4706Mike Lockwood
2674b322ce4fb86b5a7a6e50633a3a9f498ca8d4706Mike Lockwood    private int[] getSupportedDeviceProperties() {
26859e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood        return new int[] {
26959e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood            MtpConstants.DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER,
27059e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood            MtpConstants.DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME,
27159e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood        };
2724b322ce4fb86b5a7a6e50633a3a9f498ca8d4706Mike Lockwood    }
2734b322ce4fb86b5a7a6e50633a3a9f498ca8d4706Mike Lockwood
274d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private int getObjectProperty(int handle, int property,
275d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                            long[] outIntValue, char[] outStringValue) {
276d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        Log.d(TAG, "getObjectProperty: " + property);
277b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood        String column = null;
278b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood        boolean isString = false;
279b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood
280b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood        switch (property) {
2815367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood            case MtpConstants.PROPERTY_STORAGE_ID:
282b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                outIntValue[0] = mStorageID;
2835367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood                return MtpConstants.RESPONSE_OK;
2845367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood            case MtpConstants.PROPERTY_OBJECT_FORMAT:
2853b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood                column = Files.FileColumns.FORMAT;
286b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                break;
2875367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood            case MtpConstants.PROPERTY_PROTECTION_STATUS:
288828d19dd96b05fa99abdc517701e5366543c324fMike Lockwood                // protection status is always 0
289828d19dd96b05fa99abdc517701e5366543c324fMike Lockwood                outIntValue[0] = 0;
2905367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood                return MtpConstants.RESPONSE_OK;
2915367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood            case MtpConstants.PROPERTY_OBJECT_SIZE:
2923b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood                column = Files.FileColumns.SIZE;
293b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                break;
2945367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood            case MtpConstants.PROPERTY_OBJECT_FILE_NAME:
2953b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood                column = Files.FileColumns.DATA;
296b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                isString = true;
297b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                break;
2985367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood            case MtpConstants.PROPERTY_DATE_MODIFIED:
2993b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood                column = Files.FileColumns.DATE_MODIFIED;
300b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                break;
3015367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood            case MtpConstants.PROPERTY_PARENT_OBJECT:
3023b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood                column = Files.FileColumns.PARENT;
303b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                break;
3045367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood            case MtpConstants.PROPERTY_PERSISTENT_UID:
305828d19dd96b05fa99abdc517701e5366543c324fMike Lockwood                // PUID is concatenation of storageID and object handle
306828d19dd96b05fa99abdc517701e5366543c324fMike Lockwood                long puid = mStorageID;
307828d19dd96b05fa99abdc517701e5366543c324fMike Lockwood                puid <<= 32;
308828d19dd96b05fa99abdc517701e5366543c324fMike Lockwood                puid += handle;
309828d19dd96b05fa99abdc517701e5366543c324fMike Lockwood                outIntValue[0] = puid;
3105367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood                return MtpConstants.RESPONSE_OK;
311b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood            default:
3125367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood                return MtpConstants.RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
313b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood        }
314b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood
315b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood        Cursor c = null;
316b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood        try {
317b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood            // for now we are only reading properties from the "objects" table
318b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood            c = mMediaProvider.query(mObjectsUri,
3193b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood                            new String [] { Files.FileColumns._ID, column },
320b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                            ID_WHERE, new String[] { Integer.toString(handle) }, null);
321b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood            if (c != null && c.moveToNext()) {
322b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                if (isString) {
323b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                    String value = c.getString(1);
324b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                    int start = 0;
325b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood
3265367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood                    if (property == MtpConstants.PROPERTY_OBJECT_FILE_NAME) {
327b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                        // extract name from full path
328b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                        int lastSlash = value.lastIndexOf('/');
329b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                        if (lastSlash >= 0) {
330b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                            start = lastSlash + 1;
331b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                        }
332b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                    }
333b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                    int end = value.length();
334b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                    if (end - start > 255) {
335b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                        end = start + 255;
336b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                    }
337b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                    value.getChars(start, end, outStringValue, 0);
338b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                    outStringValue[end - start] = 0;
339b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                } else {
340b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                    outIntValue[0] = c.getLong(1);
341b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                }
3425367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood                return MtpConstants.RESPONSE_OK;
343b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood            }
344b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood        } catch (Exception e) {
3455367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood            return MtpConstants.RESPONSE_GENERAL_ERROR;
346b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood        } finally {
347b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood            if (c != null) {
348b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                c.close();
349b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood            }
350b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood        }
351b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood        // query failed if we get here
3525367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood        return MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE;
353d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    }
354d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
35559e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood    private int setObjectProperty(int handle, int property,
35659e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                            long intValue, String stringValue) {
35759e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood        Log.d(TAG, "setObjectProperty: " + property);
35859e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood        return MtpConstants.RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
35959e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood    }
36059e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood
36159e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood    private int getDeviceProperty(int property, long[] outIntValue, char[] outStringValue) {
36259e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood        Log.d(TAG, "getDeviceProperty: " + property);
36359e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood
36459e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood        switch (property) {
36559e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood            case MtpConstants.DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER:
36659e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood            case MtpConstants.DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME:
36759e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                // writable string properties kept in our device property database
36859e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                Cursor c = null;
36959e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                try {
37059e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                    c = mDevicePropDb.query("properties", DEVICE_PROPERTY_PROJECTION,
37159e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                        DEVICE_PROPERTY_WHERE, new String[] {  Integer.toString(property) },
37259e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                        null, null, null);
37359e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood
37459e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                    if (c != null && c.moveToNext()) {
37559e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                        String value = c.getString(1);
37659e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                        int length = value.length();
37759e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                        if (length > 255) {
37859e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                            length = 255;
37959e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                        }
38059e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                        value.getChars(0, length, outStringValue, 0);
38159e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                        outStringValue[length] = 0;
38259e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                    } else {
38359e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                        outStringValue[0] = 0;
38459e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                    }
38559e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                    return MtpConstants.RESPONSE_OK;
38659e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                } finally {
38759e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                    if (c != null) {
38859e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                        c.close();
38959e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                    }
39059e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                }
39159e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood        }
39259e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood
39359e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood        return MtpConstants.RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
39459e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood    }
39559e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood
39659e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood    private int setDeviceProperty(int property, long intValue, String stringValue) {
39759e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood        Log.d(TAG, "setDeviceProperty: " + property + " : " + stringValue);
39859e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood
39959e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood        switch (property) {
40059e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood            case MtpConstants.DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER:
40159e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood            case MtpConstants.DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME:
40259e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                // writable string properties kept in our device property database
40359e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                try {
40459e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                    ContentValues values = new ContentValues();
40559e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                    values.put("code", property);
40659e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                    values.put("value", stringValue);
40759e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                    mDevicePropDb.insert("properties", "code", values);
40859e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                    return MtpConstants.RESPONSE_OK;
40959e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                } catch (Exception e) {
41059e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                    return MtpConstants.RESPONSE_GENERAL_ERROR;
41159e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood                }
41259e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood        }
41359e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood
41459e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood        return MtpConstants.RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
41559e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood    }
41659e3f0db0855567a95f783f6d1ec36a7cfc4ea83Mike Lockwood
417d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private boolean getObjectInfo(int handle, int[] outStorageFormatParent,
418d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                        char[] outName, long[] outSizeModified) {
419d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        Log.d(TAG, "getObjectInfo: " + handle);
420d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        Cursor c = null;
421d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        try {
422d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            c = mMediaProvider.query(mObjectsUri, OBJECT_INFO_PROJECTION,
423d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                            ID_WHERE, new String[] {  Integer.toString(handle) }, null);
424d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            if (c != null && c.moveToNext()) {
425b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                outStorageFormatParent[0] = mStorageID;
426d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                outStorageFormatParent[1] = c.getInt(2);
427d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                outStorageFormatParent[2] = c.getInt(3);
428d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
429d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                // extract name from path
430d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                String path = c.getString(1);
431d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                int lastSlash = path.lastIndexOf('/');
432d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                int start = (lastSlash >= 0 ? lastSlash + 1 : 0);
433d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                int end = path.length();
434d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                if (end - start > 255) {
435d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                    end = start + 255;
436d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                }
437d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                path.getChars(start, end, outName, 0);
438d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                outName[end - start] = 0;
439d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
440d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                outSizeModified[0] = c.getLong(4);
441d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                outSizeModified[1] = c.getLong(5);
442d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                return true;
443d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            }
444d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        } catch (RemoteException e) {
445d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            Log.e(TAG, "RemoteException in getObjectProperty", e);
446d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        } finally {
447d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            if (c != null) {
448d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                c.close();
449d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            }
450d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        }
451d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        return false;
452d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    }
453d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
45459c777a24a2c639dfd84b7bf17e430e6d3424866Mike Lockwood    private int getObjectFilePath(int handle, char[] outFilePath, long[] outFileLength) {
455d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        Log.d(TAG, "getObjectFilePath: " + handle);
456d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        Cursor c = null;
457d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        try {
458d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            c = mMediaProvider.query(mObjectsUri, PATH_SIZE_PROJECTION,
459d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                            ID_WHERE, new String[] {  Integer.toString(handle) }, null);
460d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            if (c != null && c.moveToNext()) {
461d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                String path = c.getString(1);
462d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                path.getChars(0, path.length(), outFilePath, 0);
463d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                outFilePath[path.length()] = 0;
464d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                outFileLength[0] = c.getLong(2);
4655367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood                return MtpConstants.RESPONSE_OK;
46659c777a24a2c639dfd84b7bf17e430e6d3424866Mike Lockwood            } else {
4675367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood                return MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE;
468d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            }
469d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        } catch (RemoteException e) {
470d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            Log.e(TAG, "RemoteException in getObjectFilePath", e);
4715367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood            return MtpConstants.RESPONSE_GENERAL_ERROR;
472d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        } finally {
473d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            if (c != null) {
474d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                c.close();
475d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            }
476d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        }
477d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    }
478d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
47959c777a24a2c639dfd84b7bf17e430e6d3424866Mike Lockwood    private int deleteFile(int handle) {
480d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        Log.d(TAG, "deleteFile: " + handle);
4812837eefc5459427138c080d445bb491c75630163Mike Lockwood        mDatabaseModified = true;
4823b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood        Uri uri = Files.getContentUri(mVolumeName, handle);
483d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        try {
48459c777a24a2c639dfd84b7bf17e430e6d3424866Mike Lockwood            if (mMediaProvider.delete(uri, null, null) == 1) {
4855367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood                return MtpConstants.RESPONSE_OK;
48659c777a24a2c639dfd84b7bf17e430e6d3424866Mike Lockwood            } else {
4875367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood                return MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE;
48859c777a24a2c639dfd84b7bf17e430e6d3424866Mike Lockwood            }
489d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        } catch (RemoteException e) {
490d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            Log.e(TAG, "RemoteException in deleteFile", e);
4915367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood            return MtpConstants.RESPONSE_GENERAL_ERROR;
492d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        }
493d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    }
494d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
4959a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood    private int[] getObjectReferences(int handle) {
4969a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood        Log.d(TAG, "getObjectReferences for: " + handle);
4973b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood        Uri uri = Files.getReferencesUri(mVolumeName, handle);
4989a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood        Cursor c = null;
4999a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood        try {
5009a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            c = mMediaProvider.query(uri, ID_PROJECTION, null, null, null);
5019a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            if (c == null) {
5029a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                return null;
5039a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            }
5049a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            int count = c.getCount();
5059a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            if (count > 0) {
5069a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                int[] result = new int[count];
5079a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                for (int i = 0; i < count; i++) {
5089a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                    c.moveToNext();
5099a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                    result[i] = c.getInt(0);
5109a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                }
5119a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                return result;
5129a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            }
5139a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood        } catch (RemoteException e) {
5149a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            Log.e(TAG, "RemoteException in getObjectList", e);
5159a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood        } finally {
5169a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            if (c != null) {
5179a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood                c.close();
5189a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            }
5199a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood        }
5209a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood        return null;
5219a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood    }
5229a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood
5239a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood    private int setObjectReferences(int handle, int[] references) {
5242837eefc5459427138c080d445bb491c75630163Mike Lockwood        mDatabaseModified = true;
5253b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood        Uri uri = Files.getReferencesUri(mVolumeName, handle);
5269a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood        int count = references.length;
5279a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood        ContentValues[] valuesList = new ContentValues[count];
5289a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood        for (int i = 0; i < count; i++) {
5299a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            ContentValues values = new ContentValues();
5303b2a62e5b35ea5f8da9d9bee52f75c9c2ebb4eceMike Lockwood            values.put(Files.FileColumns._ID, references[i]);
5319a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            valuesList[i] = values;
5329a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood        }
5339a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood        try {
5349a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            if (count == mMediaProvider.bulkInsert(uri, valuesList)) {
5355367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood                return MtpConstants.RESPONSE_OK;
5369a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            }
5379a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood        } catch (RemoteException e) {
5389a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood            Log.e(TAG, "RemoteException in setObjectReferences", e);
5399a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood        }
5405367ab6aab2a61aaf534b18576dcdd0bca1b9681Mike Lockwood        return MtpConstants.RESPONSE_GENERAL_ERROR;
5419a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood    }
5429a2046fb5ceeee4d5334274cbff15f1058bb3244Mike Lockwood
5432837eefc5459427138c080d445bb491c75630163Mike Lockwood    private void sessionStarted() {
5442837eefc5459427138c080d445bb491c75630163Mike Lockwood        Log.d(TAG, "sessionStarted");
5452837eefc5459427138c080d445bb491c75630163Mike Lockwood        mDatabaseModified = false;
5462837eefc5459427138c080d445bb491c75630163Mike Lockwood    }
5472837eefc5459427138c080d445bb491c75630163Mike Lockwood
5482837eefc5459427138c080d445bb491c75630163Mike Lockwood    private void sessionEnded() {
5492837eefc5459427138c080d445bb491c75630163Mike Lockwood        Log.d(TAG, "sessionEnded");
5502837eefc5459427138c080d445bb491c75630163Mike Lockwood        if (mDatabaseModified) {
5512837eefc5459427138c080d445bb491c75630163Mike Lockwood            Log.d(TAG, "sending ACTION_MTP_SESSION_END");
5522837eefc5459427138c080d445bb491c75630163Mike Lockwood            mContext.sendBroadcast(new Intent(Mtp.ACTION_MTP_SESSION_END));
5532837eefc5459427138c080d445bb491c75630163Mike Lockwood            mDatabaseModified = false;
5542837eefc5459427138c080d445bb491c75630163Mike Lockwood        }
5552837eefc5459427138c080d445bb491c75630163Mike Lockwood    }
5562837eefc5459427138c080d445bb491c75630163Mike Lockwood
557d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    // used by the JNI code
558d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private int mNativeContext;
559d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
560d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private native final void native_setup();
561d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private native final void native_finalize();
562d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood}
563