MtpDatabase.java revision d815f79766984fce499e147ecbacc01914683f74
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.media;
18
19import android.content.Context;
20import android.content.ContentValues;
21import android.content.IContentProvider;
22import android.database.Cursor;
23import android.net.Uri;
24import android.os.RemoteException;
25import android.provider.MediaStore.MtpObjects;
26import android.util.Log;
27
28/**
29 * {@hide}
30 */
31public class MtpDatabase {
32
33    private static final String TAG = "MtpDatabase";
34
35    private final IContentProvider mMediaProvider;
36    private final String mVolumeName;
37    private final Uri mObjectsUri;
38
39    private static final String[] ID_PROJECTION = new String[] {
40            MtpObjects.ObjectColumns._ID, // 0
41    };
42    private static final String[] PATH_SIZE_PROJECTION = new String[] {
43            MtpObjects.ObjectColumns._ID, // 0
44            MtpObjects.ObjectColumns.DATA, // 1
45            MtpObjects.ObjectColumns.SIZE, // 2
46    };
47    private static final String[] OBJECT_INFO_PROJECTION = new String[] {
48            MtpObjects.ObjectColumns._ID, // 0
49            MtpObjects.ObjectColumns.DATA, // 1
50            MtpObjects.ObjectColumns.FORMAT, // 2
51            MtpObjects.ObjectColumns.PARENT, // 3
52            MtpObjects.ObjectColumns.SIZE, // 4
53            MtpObjects.ObjectColumns.DATE_MODIFIED, // 5
54    };
55    private static final String ID_WHERE = MtpObjects.ObjectColumns._ID + "=?";
56    private static final String PATH_WHERE = MtpObjects.ObjectColumns.DATA + "=?";
57    private static final String PARENT_WHERE = MtpObjects.ObjectColumns.PARENT + "=?";
58    private static final String PARENT_FORMAT_WHERE = PARENT_WHERE + " AND "
59                                            + MtpObjects.ObjectColumns.FORMAT + "=?";
60
61    private final MediaScanner mMediaScanner;
62
63    static {
64        System.loadLibrary("media_jni");
65    }
66
67    public MtpDatabase(Context context, String volumeName) {
68        native_setup();
69
70        mMediaProvider = context.getContentResolver().acquireProvider("media");
71        mVolumeName = volumeName;
72        mObjectsUri = MtpObjects.getContentUri(volumeName);
73        mMediaScanner = new MediaScanner(context);
74    }
75
76    @Override
77    protected void finalize() {
78        native_finalize();
79    }
80
81    private int beginSendObject(String path, int format, int parent,
82                         int storage, long size, long modified) {
83        ContentValues values = new ContentValues();
84        values.put(MtpObjects.ObjectColumns.DATA, path);
85        values.put(MtpObjects.ObjectColumns.FORMAT, format);
86        values.put(MtpObjects.ObjectColumns.PARENT, parent);
87        // storage is ignored for now
88        values.put(MtpObjects.ObjectColumns.SIZE, size);
89        values.put(MtpObjects.ObjectColumns.DATE_MODIFIED, modified);
90
91        try {
92            Uri uri = mMediaProvider.insert(mObjectsUri, values);
93            if (uri != null) {
94                return Integer.parseInt(uri.getPathSegments().get(2));
95            } else {
96                return -1;
97            }
98        } catch (RemoteException e) {
99            Log.e(TAG, "RemoteException in beginSendObject", e);
100            return -1;
101        }
102    }
103
104    private void endSendObject(String path, int handle, int format, boolean succeeded) {
105        if (succeeded) {
106            Uri uri = mMediaScanner.scanMtpFile(path, mVolumeName, handle, format);
107        } else {
108            deleteFile(handle);
109        }
110    }
111
112    private int[] getObjectList(int storageID, int format, int parent) {
113        // we can ignore storageID until we support multiple storages
114        Log.d(TAG, "getObjectList parent: " + parent);
115        Cursor c = null;
116        try {
117            if (format != 0) {
118                c = mMediaProvider.query(mObjectsUri, ID_PROJECTION,
119                            PARENT_FORMAT_WHERE,
120                            new String[] { Integer.toString(parent), Integer.toString(format) },
121                             null);
122            } else {
123                c = mMediaProvider.query(mObjectsUri, ID_PROJECTION,
124                            PARENT_WHERE, new String[] { Integer.toString(parent) }, null);
125            }
126            if (c == null) {
127                Log.d(TAG, "null cursor");
128                return null;
129            }
130            int count = c.getCount();
131            if (count > 0) {
132                int[] result = new int[count];
133                for (int i = 0; i < count; i++) {
134                    c.moveToNext();
135                    result[i] = c.getInt(0);
136                }
137                Log.d(TAG, "returning " + result);
138                return result;
139            }
140        } catch (RemoteException e) {
141            Log.e(TAG, "RemoteException in getObjectList", e);
142        } finally {
143            if (c != null) {
144                c.close();
145            }
146        }
147        return null;
148    }
149
150    private int getObjectProperty(int handle, int property,
151                            long[] outIntValue, char[] outStringValue) {
152        Log.d(TAG, "getObjectProperty: " + property);
153        return 0;
154    }
155
156    private boolean getObjectInfo(int handle, int[] outStorageFormatParent,
157                        char[] outName, long[] outSizeModified) {
158        Log.d(TAG, "getObjectInfo: " + handle);
159        Cursor c = null;
160        try {
161            c = mMediaProvider.query(mObjectsUri, OBJECT_INFO_PROJECTION,
162                            ID_WHERE, new String[] {  Integer.toString(handle) }, null);
163            if (c != null && c.moveToNext()) {
164                outStorageFormatParent[0] = 0x00010001;
165                outStorageFormatParent[1] = c.getInt(2);
166                outStorageFormatParent[2] = c.getInt(3);
167
168                // extract name from path
169                String path = c.getString(1);
170                int lastSlash = path.lastIndexOf('/');
171                int start = (lastSlash >= 0 ? lastSlash + 1 : 0);
172                int end = path.length();
173                if (end - start > 255) {
174                    end = start + 255;
175                }
176                path.getChars(start, end, outName, 0);
177                outName[end - start] = 0;
178
179                outSizeModified[0] = c.getLong(4);
180                outSizeModified[1] = c.getLong(5);
181                return true;
182            }
183        } catch (RemoteException e) {
184            Log.e(TAG, "RemoteException in getObjectProperty", e);
185        } finally {
186            if (c != null) {
187                c.close();
188            }
189        }
190        return false;
191    }
192
193    private boolean getObjectFilePath(int handle, char[] outFilePath, long[] outFileLength) {
194        Log.d(TAG, "getObjectFilePath: " + handle);
195        Cursor c = null;
196        try {
197            c = mMediaProvider.query(mObjectsUri, PATH_SIZE_PROJECTION,
198                            ID_WHERE, new String[] {  Integer.toString(handle) }, null);
199            if (c != null && c.moveToNext()) {
200                String path = c.getString(1);
201                path.getChars(0, path.length(), outFilePath, 0);
202                outFilePath[path.length()] = 0;
203                outFileLength[0] = c.getLong(2);
204                return true;
205            }
206        } catch (RemoteException e) {
207            Log.e(TAG, "RemoteException in getObjectFilePath", e);
208        } finally {
209            if (c != null) {
210                c.close();
211            }
212        }
213        return false;
214    }
215
216    private boolean deleteFile(int handle) {
217        Log.d(TAG, "deleteFile: " + handle);
218        Uri uri = MtpObjects.getContentUri(mVolumeName, handle);
219        try {
220            return (mMediaProvider.delete(uri, null, null) == 1);
221        } catch (RemoteException e) {
222            Log.e(TAG, "RemoteException in deleteFile", e);
223            return false;
224        }
225    }
226
227    // used by the JNI code
228    private int mNativeContext;
229
230    private native final void native_setup();
231    private native final void native_finalize();
232}
233