MtpDatabase.java revision 59c777a24a2c639dfd84b7bf17e430e6d3424866
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;
22d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwoodimport android.database.Cursor;
23d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwoodimport android.net.Uri;
24d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwoodimport android.os.RemoteException;
25d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwoodimport android.provider.MediaStore.MtpObjects;
26d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwoodimport android.util.Log;
27d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
28d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood/**
29d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood * {@hide}
30d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood */
31d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwoodpublic class MtpDatabase {
32d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
33d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private static final String TAG = "MtpDatabase";
34d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
35d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private final IContentProvider mMediaProvider;
36d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private final String mVolumeName;
37d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private final Uri mObjectsUri;
38d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
39b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood    // FIXME - this should be passed in via the constructor
40b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood    private final int mStorageID = 0x00010001;
41b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood
42d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private static final String[] ID_PROJECTION = new String[] {
43d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            MtpObjects.ObjectColumns._ID, // 0
44d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    };
45d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private static final String[] PATH_SIZE_PROJECTION = new String[] {
46d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            MtpObjects.ObjectColumns._ID, // 0
47d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            MtpObjects.ObjectColumns.DATA, // 1
48d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            MtpObjects.ObjectColumns.SIZE, // 2
49d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    };
50d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private static final String[] OBJECT_INFO_PROJECTION = new String[] {
51d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            MtpObjects.ObjectColumns._ID, // 0
52d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            MtpObjects.ObjectColumns.DATA, // 1
53d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            MtpObjects.ObjectColumns.FORMAT, // 2
54d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            MtpObjects.ObjectColumns.PARENT, // 3
55d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            MtpObjects.ObjectColumns.SIZE, // 4
56d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            MtpObjects.ObjectColumns.DATE_MODIFIED, // 5
57d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    };
58d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private static final String ID_WHERE = MtpObjects.ObjectColumns._ID + "=?";
59d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private static final String PATH_WHERE = MtpObjects.ObjectColumns.DATA + "=?";
60d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private static final String PARENT_WHERE = MtpObjects.ObjectColumns.PARENT + "=?";
61d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private static final String PARENT_FORMAT_WHERE = PARENT_WHERE + " AND "
62d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                                            + MtpObjects.ObjectColumns.FORMAT + "=?";
63d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
64d815f79766984fce499e147ecbacc01914683f74Mike Lockwood    private final MediaScanner mMediaScanner;
65d815f79766984fce499e147ecbacc01914683f74Mike Lockwood
66b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood    // MTP property codes
67b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood    private static final int MTP_PROPERTY_STORAGE_ID = 0xDC01;
68b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood    private static final int MTP_PROPERTY_OBJECT_FORMAT = 0xDC02;
69b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood    private static final int MTP_PROPERTY_OBJECT_SIZE = 0xDC04;
70b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood    private static final int MTP_PROPERTY_OBJECT_FILE_NAME = 0xDC07;
71b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood    private static final int MTP_PROPERTY_DATE_MODIFIED = 0xDC09;
72b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood    private static final int MTP_PROPERTY_PARENT_OBJECT = 0xDC0B;
73b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood
74b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood    // MTP response codes
75b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood    private static final int MTP_RESPONSE_OK = 0x2001;
76b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood    private static final int MTP_RESPONSE_GENERAL_ERROR = 0x2002;
77b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood    private static final int MTP_RESPONSE_INVALID_OBJECT_HANDLE = 0x2009;
78b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood    private static final int MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED = 0xA80A;
79b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood
80d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    static {
81d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        System.loadLibrary("media_jni");
82d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    }
83d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
84d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    public MtpDatabase(Context context, String volumeName) {
85d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        native_setup();
86d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
87d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        mMediaProvider = context.getContentResolver().acquireProvider("media");
88d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        mVolumeName = volumeName;
89d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        mObjectsUri = MtpObjects.getContentUri(volumeName);
90d815f79766984fce499e147ecbacc01914683f74Mike Lockwood        mMediaScanner = new MediaScanner(context);
91d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    }
92d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
93d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    @Override
94d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    protected void finalize() {
95d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        native_finalize();
96d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    }
97d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
98d815f79766984fce499e147ecbacc01914683f74Mike Lockwood    private int beginSendObject(String path, int format, int parent,
99d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                         int storage, long size, long modified) {
100d815f79766984fce499e147ecbacc01914683f74Mike Lockwood        ContentValues values = new ContentValues();
101d815f79766984fce499e147ecbacc01914683f74Mike Lockwood        values.put(MtpObjects.ObjectColumns.DATA, path);
102d815f79766984fce499e147ecbacc01914683f74Mike Lockwood        values.put(MtpObjects.ObjectColumns.FORMAT, format);
103d815f79766984fce499e147ecbacc01914683f74Mike Lockwood        values.put(MtpObjects.ObjectColumns.PARENT, parent);
104d815f79766984fce499e147ecbacc01914683f74Mike Lockwood        // storage is ignored for now
105d815f79766984fce499e147ecbacc01914683f74Mike Lockwood        values.put(MtpObjects.ObjectColumns.SIZE, size);
106d815f79766984fce499e147ecbacc01914683f74Mike Lockwood        values.put(MtpObjects.ObjectColumns.DATE_MODIFIED, modified);
107d815f79766984fce499e147ecbacc01914683f74Mike Lockwood
108d815f79766984fce499e147ecbacc01914683f74Mike Lockwood        try {
109d815f79766984fce499e147ecbacc01914683f74Mike Lockwood            Uri uri = mMediaProvider.insert(mObjectsUri, values);
110d815f79766984fce499e147ecbacc01914683f74Mike Lockwood            if (uri != null) {
111d815f79766984fce499e147ecbacc01914683f74Mike Lockwood                return Integer.parseInt(uri.getPathSegments().get(2));
112d815f79766984fce499e147ecbacc01914683f74Mike Lockwood            } else {
113d815f79766984fce499e147ecbacc01914683f74Mike Lockwood                return -1;
114d815f79766984fce499e147ecbacc01914683f74Mike Lockwood            }
115d815f79766984fce499e147ecbacc01914683f74Mike Lockwood        } catch (RemoteException e) {
116d815f79766984fce499e147ecbacc01914683f74Mike Lockwood            Log.e(TAG, "RemoteException in beginSendObject", e);
117d815f79766984fce499e147ecbacc01914683f74Mike Lockwood            return -1;
118d815f79766984fce499e147ecbacc01914683f74Mike Lockwood        }
119d815f79766984fce499e147ecbacc01914683f74Mike Lockwood    }
120d815f79766984fce499e147ecbacc01914683f74Mike Lockwood
121d815f79766984fce499e147ecbacc01914683f74Mike Lockwood    private void endSendObject(String path, int handle, int format, boolean succeeded) {
122d815f79766984fce499e147ecbacc01914683f74Mike Lockwood        if (succeeded) {
123d815f79766984fce499e147ecbacc01914683f74Mike Lockwood            Uri uri = mMediaScanner.scanMtpFile(path, mVolumeName, handle, format);
124d815f79766984fce499e147ecbacc01914683f74Mike Lockwood        } else {
125d815f79766984fce499e147ecbacc01914683f74Mike Lockwood            deleteFile(handle);
126d815f79766984fce499e147ecbacc01914683f74Mike Lockwood        }
127d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    }
128d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
129d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private int[] getObjectList(int storageID, int format, int parent) {
130d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        // we can ignore storageID until we support multiple storages
131d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        Log.d(TAG, "getObjectList parent: " + parent);
132d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        Cursor c = null;
133d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        try {
134d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            if (format != 0) {
135d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                c = mMediaProvider.query(mObjectsUri, ID_PROJECTION,
136d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                            PARENT_FORMAT_WHERE,
137d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                            new String[] { Integer.toString(parent), Integer.toString(format) },
138d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                             null);
139d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            } else {
140d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                c = mMediaProvider.query(mObjectsUri, ID_PROJECTION,
141d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                            PARENT_WHERE, new String[] { Integer.toString(parent) }, null);
142d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            }
143d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            if (c == null) {
144d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                Log.d(TAG, "null cursor");
145d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                return null;
146d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            }
147d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            int count = c.getCount();
148d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            if (count > 0) {
149d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                int[] result = new int[count];
150d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                for (int i = 0; i < count; i++) {
151d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                    c.moveToNext();
152d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                    result[i] = c.getInt(0);
153d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                }
154d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                Log.d(TAG, "returning " + result);
155d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                return result;
156d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            }
157d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        } catch (RemoteException e) {
158d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            Log.e(TAG, "RemoteException in getObjectList", e);
159d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        } finally {
160d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            if (c != null) {
161d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                c.close();
162d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            }
163d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        }
164d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        return null;
165d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    }
166d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
167d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private int getObjectProperty(int handle, int property,
168d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                            long[] outIntValue, char[] outStringValue) {
169d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        Log.d(TAG, "getObjectProperty: " + property);
170b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood        String column = null;
171b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood        boolean isString = false;
172b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood
173b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood        switch (property) {
174b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood            case MTP_PROPERTY_STORAGE_ID:
175b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                outIntValue[0] = mStorageID;
176b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                return MTP_RESPONSE_OK;
177b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood            case MTP_PROPERTY_OBJECT_FORMAT:
178b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                column = MtpObjects.ObjectColumns.FORMAT;
179b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                break;
180b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood            case MTP_PROPERTY_OBJECT_SIZE:
181b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                column = MtpObjects.ObjectColumns.SIZE;
182b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                break;
183b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood            case MTP_PROPERTY_OBJECT_FILE_NAME:
184b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                column = MtpObjects.ObjectColumns.DATA;
185b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                isString = true;
186b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                break;
187b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood            case MTP_PROPERTY_DATE_MODIFIED:
188b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                column = MtpObjects.ObjectColumns.DATE_MODIFIED;
189b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                break;
190b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood            case MTP_PROPERTY_PARENT_OBJECT:
191b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                column = MtpObjects.ObjectColumns.PARENT;
192b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                break;
193b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood            default:
194b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                return MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
195b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood        }
196b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood
197b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood        Cursor c = null;
198b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood        try {
199b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood            // for now we are only reading properties from the "objects" table
200b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood            c = mMediaProvider.query(mObjectsUri,
201b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                            new String [] { MtpObjects.ObjectColumns._ID, column },
202b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                            ID_WHERE, new String[] { Integer.toString(handle) }, null);
203b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood            if (c != null && c.moveToNext()) {
204b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                if (isString) {
205b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                    String value = c.getString(1);
206b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                    int start = 0;
207b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood
208b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                    if (property == MTP_PROPERTY_OBJECT_FILE_NAME) {
209b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                        // extract name from full path
210b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                        int lastSlash = value.lastIndexOf('/');
211b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                        if (lastSlash >= 0) {
212b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                            start = lastSlash + 1;
213b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                        }
214b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                    }
215b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                    int end = value.length();
216b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                    if (end - start > 255) {
217b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                        end = start + 255;
218b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                    }
219b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                    value.getChars(start, end, outStringValue, 0);
220b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                    outStringValue[end - start] = 0;
221b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                } else {
222b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                    outIntValue[0] = c.getLong(1);
223b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                }
224b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                return MTP_RESPONSE_OK;
225b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood            }
226b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood        } catch (Exception e) {
227b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood            return MTP_RESPONSE_GENERAL_ERROR;
228b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood        } finally {
229b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood            if (c != null) {
230b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                c.close();
231b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood            }
232b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood        }
233b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood        // query failed if we get here
234b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood        return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
235d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    }
236d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
237d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private boolean getObjectInfo(int handle, int[] outStorageFormatParent,
238d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                        char[] outName, long[] outSizeModified) {
239d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        Log.d(TAG, "getObjectInfo: " + handle);
240d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        Cursor c = null;
241d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        try {
242d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            c = mMediaProvider.query(mObjectsUri, OBJECT_INFO_PROJECTION,
243d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                            ID_WHERE, new String[] {  Integer.toString(handle) }, null);
244d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            if (c != null && c.moveToNext()) {
245b2cada9034436b4ea4bac218da7a1e29460d15b2Mike Lockwood                outStorageFormatParent[0] = mStorageID;
246d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                outStorageFormatParent[1] = c.getInt(2);
247d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                outStorageFormatParent[2] = c.getInt(3);
248d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
249d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                // extract name from path
250d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                String path = c.getString(1);
251d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                int lastSlash = path.lastIndexOf('/');
252d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                int start = (lastSlash >= 0 ? lastSlash + 1 : 0);
253d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                int end = path.length();
254d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                if (end - start > 255) {
255d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                    end = start + 255;
256d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                }
257d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                path.getChars(start, end, outName, 0);
258d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                outName[end - start] = 0;
259d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
260d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                outSizeModified[0] = c.getLong(4);
261d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                outSizeModified[1] = c.getLong(5);
262d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                return true;
263d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            }
264d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        } catch (RemoteException e) {
265d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            Log.e(TAG, "RemoteException in getObjectProperty", e);
266d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        } finally {
267d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            if (c != null) {
268d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                c.close();
269d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            }
270d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        }
271d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        return false;
272d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    }
273d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
27459c777a24a2c639dfd84b7bf17e430e6d3424866Mike Lockwood    private int getObjectFilePath(int handle, char[] outFilePath, long[] outFileLength) {
275d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        Log.d(TAG, "getObjectFilePath: " + handle);
276d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        Cursor c = null;
277d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        try {
278d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            c = mMediaProvider.query(mObjectsUri, PATH_SIZE_PROJECTION,
279d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                            ID_WHERE, new String[] {  Integer.toString(handle) }, null);
280d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            if (c != null && c.moveToNext()) {
281d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                String path = c.getString(1);
282d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                path.getChars(0, path.length(), outFilePath, 0);
283d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                outFilePath[path.length()] = 0;
284d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                outFileLength[0] = c.getLong(2);
28559c777a24a2c639dfd84b7bf17e430e6d3424866Mike Lockwood                return MTP_RESPONSE_OK;
28659c777a24a2c639dfd84b7bf17e430e6d3424866Mike Lockwood            } else {
28759c777a24a2c639dfd84b7bf17e430e6d3424866Mike Lockwood                return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
288d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            }
289d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        } catch (RemoteException e) {
290d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            Log.e(TAG, "RemoteException in getObjectFilePath", e);
29159c777a24a2c639dfd84b7bf17e430e6d3424866Mike Lockwood            return MTP_RESPONSE_GENERAL_ERROR;
292d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        } finally {
293d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            if (c != null) {
294d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood                c.close();
295d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            }
296d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        }
297d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    }
298d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
29959c777a24a2c639dfd84b7bf17e430e6d3424866Mike Lockwood    private int deleteFile(int handle) {
300d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        Log.d(TAG, "deleteFile: " + handle);
301d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        Uri uri = MtpObjects.getContentUri(mVolumeName, handle);
302d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        try {
30359c777a24a2c639dfd84b7bf17e430e6d3424866Mike Lockwood            if (mMediaProvider.delete(uri, null, null) == 1) {
30459c777a24a2c639dfd84b7bf17e430e6d3424866Mike Lockwood                return MTP_RESPONSE_OK;
30559c777a24a2c639dfd84b7bf17e430e6d3424866Mike Lockwood            } else {
30659c777a24a2c639dfd84b7bf17e430e6d3424866Mike Lockwood                return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
30759c777a24a2c639dfd84b7bf17e430e6d3424866Mike Lockwood            }
308d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        } catch (RemoteException e) {
309d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood            Log.e(TAG, "RemoteException in deleteFile", e);
31059c777a24a2c639dfd84b7bf17e430e6d3424866Mike Lockwood            return MTP_RESPONSE_GENERAL_ERROR;
311d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood        }
312d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    }
313d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
314d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    // used by the JNI code
315d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private int mNativeContext;
316d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood
317d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private native final void native_setup();
318d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood    private native final void native_finalize();
319d21eac9c70940f2c73da5faaf401dbbc44b70a15Mike Lockwood}
320