blob: 77d0f34f1ad6a4f6df6e31560af52702f9e34120 [file] [log] [blame]
Mike Lockwood7d7fb632010-12-01 18:46:23 -05001/*
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
Mike Lockwood0cd01362010-12-30 11:54:33 -050017package android.mtp;
Mike Lockwood7d7fb632010-12-01 18:46:23 -050018
Jeff Sharkey60cfad82016-01-05 17:30:57 -070019import android.content.ContentProviderClient;
Mike Lockwood7d7fb632010-12-01 18:46:23 -050020import android.database.Cursor;
21import android.net.Uri;
22import android.os.RemoteException;
Mike Lockwood7d7fb632010-12-01 18:46:23 -050023import android.provider.MediaStore.Audio;
24import android.provider.MediaStore.Files;
25import android.provider.MediaStore.Images;
Mike Lockwood7d7fb632010-12-01 18:46:23 -050026import android.util.Log;
27
28import java.util.ArrayList;
29
Jerry Zhangf9c5c252017-08-16 18:07:51 -070030/**
31 * MtpPropertyGroup represents a list of MTP properties.
32 * {@hide}
33 */
Mike Lockwood7d7fb632010-12-01 18:46:23 -050034class MtpPropertyGroup {
Jerry Zhangf9c5c252017-08-16 18:07:51 -070035 private static final String TAG = MtpPropertyGroup.class.getSimpleName();
Mike Lockwood7d7fb632010-12-01 18:46:23 -050036
37 private class Property {
Jerry Zhangf9c5c252017-08-16 18:07:51 -070038 int code;
39 int type;
40 int column;
Mike Lockwood7d7fb632010-12-01 18:46:23 -050041
42 Property(int code, int type, int column) {
43 this.code = code;
44 this.type = type;
45 this.column = column;
46 }
47 }
48
Jeff Sharkey60cfad82016-01-05 17:30:57 -070049 private final ContentProviderClient mProvider;
Mike Lockwood7d7fb632010-12-01 18:46:23 -050050 private final String mVolumeName;
51 private final Uri mUri;
52
53 // list of all properties in this group
Jerry Zhangf9c5c252017-08-16 18:07:51 -070054 private final Property[] mProperties;
Mike Lockwood7d7fb632010-12-01 18:46:23 -050055
56 // list of columns for database query
Jerry Zhangf9c5c252017-08-16 18:07:51 -070057 private String[] mColumns;
Mike Lockwood7d7fb632010-12-01 18:46:23 -050058
Jerry Zhangf9c5c252017-08-16 18:07:51 -070059 private static final String PATH_WHERE = Files.FileColumns.DATA + "=?";
60
Mike Lockwood7d7fb632010-12-01 18:46:23 -050061 // constructs a property group for a list of properties
Jerry Zhangf9c5c252017-08-16 18:07:51 -070062 public MtpPropertyGroup(ContentProviderClient provider, String volumeName, int[] properties) {
Mike Lockwood7d7fb632010-12-01 18:46:23 -050063 mProvider = provider;
Jeff Sharkey60cfad82016-01-05 17:30:57 -070064 mVolumeName = volumeName;
65 mUri = Files.getMtpObjectsUri(volumeName);
Mike Lockwood7d7fb632010-12-01 18:46:23 -050066
67 int count = properties.length;
Jerry Zhangf9c5c252017-08-16 18:07:51 -070068 ArrayList<String> columns = new ArrayList<>(count);
Mike Lockwood7d7fb632010-12-01 18:46:23 -050069 columns.add(Files.FileColumns._ID);
70
71 mProperties = new Property[count];
72 for (int i = 0; i < count; i++) {
73 mProperties[i] = createProperty(properties[i], columns);
74 }
75 count = columns.size();
76 mColumns = new String[count];
77 for (int i = 0; i < count; i++) {
78 mColumns[i] = columns.get(i);
79 }
80 }
81
82 private Property createProperty(int code, ArrayList<String> columns) {
83 String column = null;
84 int type;
85
Jerry Zhangf9c5c252017-08-16 18:07:51 -070086 switch (code) {
Mike Lockwood7d7fb632010-12-01 18:46:23 -050087 case MtpConstants.PROPERTY_STORAGE_ID:
Mike Lockwood7d7fb632010-12-01 18:46:23 -050088 type = MtpConstants.TYPE_UINT32;
89 break;
Jerry Zhangf9c5c252017-08-16 18:07:51 -070090 case MtpConstants.PROPERTY_OBJECT_FORMAT:
Mike Lockwood7d7fb632010-12-01 18:46:23 -050091 type = MtpConstants.TYPE_UINT16;
92 break;
93 case MtpConstants.PROPERTY_PROTECTION_STATUS:
Mike Lockwood7d7fb632010-12-01 18:46:23 -050094 type = MtpConstants.TYPE_UINT16;
95 break;
96 case MtpConstants.PROPERTY_OBJECT_SIZE:
Mike Lockwood7d7fb632010-12-01 18:46:23 -050097 type = MtpConstants.TYPE_UINT64;
98 break;
99 case MtpConstants.PROPERTY_OBJECT_FILE_NAME:
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500100 type = MtpConstants.TYPE_STR;
101 break;
102 case MtpConstants.PROPERTY_NAME:
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500103 type = MtpConstants.TYPE_STR;
104 break;
105 case MtpConstants.PROPERTY_DATE_MODIFIED:
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500106 type = MtpConstants.TYPE_STR;
107 break;
108 case MtpConstants.PROPERTY_DATE_ADDED:
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500109 type = MtpConstants.TYPE_STR;
110 break;
111 case MtpConstants.PROPERTY_ORIGINAL_RELEASE_DATE:
112 column = Audio.AudioColumns.YEAR;
113 type = MtpConstants.TYPE_STR;
114 break;
115 case MtpConstants.PROPERTY_PARENT_OBJECT:
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500116 type = MtpConstants.TYPE_UINT32;
117 break;
118 case MtpConstants.PROPERTY_PERSISTENT_UID:
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500119 type = MtpConstants.TYPE_UINT128;
120 break;
121 case MtpConstants.PROPERTY_DURATION:
122 column = Audio.AudioColumns.DURATION;
123 type = MtpConstants.TYPE_UINT32;
124 break;
125 case MtpConstants.PROPERTY_TRACK:
126 column = Audio.AudioColumns.TRACK;
127 type = MtpConstants.TYPE_UINT16;
128 break;
129 case MtpConstants.PROPERTY_DISPLAY_NAME:
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500130 type = MtpConstants.TYPE_STR;
131 break;
132 case MtpConstants.PROPERTY_ARTIST:
133 type = MtpConstants.TYPE_STR;
134 break;
135 case MtpConstants.PROPERTY_ALBUM_NAME:
136 type = MtpConstants.TYPE_STR;
137 break;
138 case MtpConstants.PROPERTY_ALBUM_ARTIST:
139 column = Audio.AudioColumns.ALBUM_ARTIST;
140 type = MtpConstants.TYPE_STR;
141 break;
142 case MtpConstants.PROPERTY_GENRE:
143 // genre requires a special query
144 type = MtpConstants.TYPE_STR;
145 break;
146 case MtpConstants.PROPERTY_COMPOSER:
147 column = Audio.AudioColumns.COMPOSER;
148 type = MtpConstants.TYPE_STR;
149 break;
150 case MtpConstants.PROPERTY_DESCRIPTION:
151 column = Images.ImageColumns.DESCRIPTION;
152 type = MtpConstants.TYPE_STR;
153 break;
Mike Lockwood71827742015-01-23 10:50:08 -0800154 case MtpConstants.PROPERTY_AUDIO_WAVE_CODEC:
155 case MtpConstants.PROPERTY_AUDIO_BITRATE:
156 case MtpConstants.PROPERTY_SAMPLE_RATE:
157 // these are special cased
158 type = MtpConstants.TYPE_UINT32;
159 break;
160 case MtpConstants.PROPERTY_BITRATE_TYPE:
161 case MtpConstants.PROPERTY_NUMBER_OF_CHANNELS:
162 // these are special cased
163 type = MtpConstants.TYPE_UINT16;
164 break;
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500165 default:
166 type = MtpConstants.TYPE_UNDEFINED;
167 Log.e(TAG, "unsupported property " + code);
168 break;
169 }
170
171 if (column != null) {
172 columns.add(column);
173 return new Property(code, type, columns.size() - 1);
174 } else {
175 return new Property(code, type, -1);
176 }
177 }
178
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700179 private String queryAudio(String path, String column) {
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500180 Cursor c = null;
181 try {
Jeff Sharkey60cfad82016-01-05 17:30:57 -0700182 c = mProvider.query(Audio.Media.getContentUri(mVolumeName),
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700183 new String [] { column },
184 PATH_WHERE, new String[] {path}, null, null);
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500185 if (c != null && c.moveToNext()) {
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700186 return c.getString(0);
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500187 } else {
188 return "";
189 }
190 } catch (Exception e) {
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700191 return "";
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500192 } finally {
193 if (c != null) {
194 c.close();
195 }
196 }
197 }
198
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700199 private String queryGenre(String path) {
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500200 Cursor c = null;
201 try {
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700202 c = mProvider.query(Audio.Genres.getContentUri(mVolumeName),
203 new String [] { Audio.GenresColumns.NAME },
204 PATH_WHERE, new String[] {path}, null, null);
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500205 if (c != null && c.moveToNext()) {
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700206 return c.getString(0);
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500207 } else {
208 return "";
209 }
210 } catch (Exception e) {
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700211 return "";
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500212 } finally {
213 if (c != null) {
214 c.close();
215 }
216 }
217 }
218
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700219 /**
220 * Gets the values of the properties represented by this property group for the given
221 * object and adds them to the given property list.
222 * @return Response_OK if the operation succeeded.
223 */
224 public int getPropertyList(MtpStorageManager.MtpObject object, MtpPropertyList list) {
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500225 Cursor c = null;
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700226 int id = object.getId();
227 String path = object.getPath().toString();
228 for (Property property : mProperties) {
229 if (property.column != -1 && c == null) {
230 try {
231 // Look up the entry in MediaProvider only if one of those properties is needed.
232 c = mProvider.query(mUri, mColumns,
233 PATH_WHERE, new String[] {path}, null, null);
234 if (c != null && !c.moveToNext()) {
235 c.close();
236 c = null;
237 }
238 } catch (RemoteException e) {
239 Log.e(TAG, "Mediaprovider lookup failed");
Mike Lockwood4356d812011-02-07 13:40:21 -0500240 }
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500241 }
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700242 switch (property.code) {
243 case MtpConstants.PROPERTY_PROTECTION_STATUS:
244 // protection status is always 0
245 list.append(id, property.code, property.type, 0);
246 break;
247 case MtpConstants.PROPERTY_NAME:
248 case MtpConstants.PROPERTY_OBJECT_FILE_NAME:
249 case MtpConstants.PROPERTY_DISPLAY_NAME:
250 list.append(id, property.code, object.getName());
251 break;
252 case MtpConstants.PROPERTY_DATE_MODIFIED:
253 case MtpConstants.PROPERTY_DATE_ADDED:
254 // convert from seconds to DateTime
255 list.append(id, property.code,
256 format_date_time(object.getModifiedTime()));
257 break;
258 case MtpConstants.PROPERTY_STORAGE_ID:
259 list.append(id, property.code, property.type, object.getStorageId());
260 break;
261 case MtpConstants.PROPERTY_OBJECT_FORMAT:
262 list.append(id, property.code, property.type, object.getFormat());
263 break;
264 case MtpConstants.PROPERTY_OBJECT_SIZE:
265 list.append(id, property.code, property.type, object.getSize());
266 break;
267 case MtpConstants.PROPERTY_PARENT_OBJECT:
268 list.append(id, property.code, property.type,
269 object.getParent().isRoot() ? 0 : object.getParent().getId());
270 break;
271 case MtpConstants.PROPERTY_PERSISTENT_UID:
272 // The persistent uid must be unique and never reused among all objects,
273 // and remain the same between sessions.
274 long puid = (object.getPath().toString().hashCode() << 32)
275 + object.getModifiedTime();
276 list.append(id, property.code, property.type, puid);
277 break;
278 case MtpConstants.PROPERTY_ORIGINAL_RELEASE_DATE:
279 // release date is stored internally as just the year
280 int year = 0;
281 if (c != null)
282 year = c.getInt(property.column);
283 String dateTime = Integer.toString(year) + "0101T000000";
284 list.append(id, property.code, dateTime);
285 break;
286 case MtpConstants.PROPERTY_TRACK:
287 int track = 0;
288 if (c != null)
289 track = c.getInt(property.column);
290 list.append(id, property.code, MtpConstants.TYPE_UINT16,
291 track % 1000);
292 break;
293 case MtpConstants.PROPERTY_ARTIST:
294 list.append(id, property.code,
295 queryAudio(path, Audio.AudioColumns.ARTIST));
296 break;
297 case MtpConstants.PROPERTY_ALBUM_NAME:
298 list.append(id, property.code,
299 queryAudio(path, Audio.AudioColumns.ALBUM));
300 break;
301 case MtpConstants.PROPERTY_GENRE:
302 String genre = queryGenre(path);
303 if (genre != null) {
304 list.append(id, property.code, genre);
305 }
306 break;
307 case MtpConstants.PROPERTY_AUDIO_WAVE_CODEC:
308 case MtpConstants.PROPERTY_AUDIO_BITRATE:
309 case MtpConstants.PROPERTY_SAMPLE_RATE:
310 // we don't have these in our database, so return 0
311 list.append(id, property.code, MtpConstants.TYPE_UINT32, 0);
312 break;
313 case MtpConstants.PROPERTY_BITRATE_TYPE:
314 case MtpConstants.PROPERTY_NUMBER_OF_CHANNELS:
315 // we don't have these in our database, so return 0
316 list.append(id, property.code, MtpConstants.TYPE_UINT16, 0);
317 break;
318 default:
319 switch(property.type) {
320 case MtpConstants.TYPE_UNDEFINED:
321 list.append(id, property.code, property.type, 0);
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500322 break;
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700323 case MtpConstants.TYPE_STR:
324 String value = "";
325 if (c != null)
326 value = c.getString(property.column);
327 list.append(id, property.code, value);
Mike Lockwood71827742015-01-23 10:50:08 -0800328 break;
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500329 default:
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700330 long longValue = 0L;
331 if (c != null)
332 longValue = c.getLong(property.column);
333 list.append(id, property.code, property.type, longValue);
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500334 }
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500335 }
336 }
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700337 if (c != null)
338 c.close();
339 return MtpConstants.RESPONSE_OK;
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500340 }
341
342 private native String format_date_time(long seconds);
343}