blob: 6d5be8ef6985fdafb901088ad22fb4b47547b2f6 [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;
Mike Lockwood7d7fb632010-12-01 18:46:23 -050051
52 // list of all properties in this group
Jerry Zhangf9c5c252017-08-16 18:07:51 -070053 private final Property[] mProperties;
Mike Lockwood7d7fb632010-12-01 18:46:23 -050054
55 // list of columns for database query
Jerry Zhangf9c5c252017-08-16 18:07:51 -070056 private String[] mColumns;
Mike Lockwood7d7fb632010-12-01 18:46:23 -050057
Jerry Zhangf9c5c252017-08-16 18:07:51 -070058 private static final String PATH_WHERE = Files.FileColumns.DATA + "=?";
59
Mike Lockwood7d7fb632010-12-01 18:46:23 -050060 // constructs a property group for a list of properties
Jerry Zhangf9c5c252017-08-16 18:07:51 -070061 public MtpPropertyGroup(ContentProviderClient provider, String volumeName, int[] properties) {
Mike Lockwood7d7fb632010-12-01 18:46:23 -050062 mProvider = provider;
Jeff Sharkey60cfad82016-01-05 17:30:57 -070063 mVolumeName = volumeName;
Mike Lockwood7d7fb632010-12-01 18:46:23 -050064
65 int count = properties.length;
Jerry Zhangf9c5c252017-08-16 18:07:51 -070066 ArrayList<String> columns = new ArrayList<>(count);
Mike Lockwood7d7fb632010-12-01 18:46:23 -050067 columns.add(Files.FileColumns._ID);
68
69 mProperties = new Property[count];
70 for (int i = 0; i < count; i++) {
71 mProperties[i] = createProperty(properties[i], columns);
72 }
73 count = columns.size();
74 mColumns = new String[count];
75 for (int i = 0; i < count; i++) {
76 mColumns[i] = columns.get(i);
77 }
78 }
79
80 private Property createProperty(int code, ArrayList<String> columns) {
81 String column = null;
82 int type;
83
Jerry Zhangf9c5c252017-08-16 18:07:51 -070084 switch (code) {
Mike Lockwood7d7fb632010-12-01 18:46:23 -050085 case MtpConstants.PROPERTY_STORAGE_ID:
Mike Lockwood7d7fb632010-12-01 18:46:23 -050086 type = MtpConstants.TYPE_UINT32;
87 break;
Jerry Zhangf9c5c252017-08-16 18:07:51 -070088 case MtpConstants.PROPERTY_OBJECT_FORMAT:
Mike Lockwood7d7fb632010-12-01 18:46:23 -050089 type = MtpConstants.TYPE_UINT16;
90 break;
91 case MtpConstants.PROPERTY_PROTECTION_STATUS:
Mike Lockwood7d7fb632010-12-01 18:46:23 -050092 type = MtpConstants.TYPE_UINT16;
93 break;
94 case MtpConstants.PROPERTY_OBJECT_SIZE:
Mike Lockwood7d7fb632010-12-01 18:46:23 -050095 type = MtpConstants.TYPE_UINT64;
96 break;
97 case MtpConstants.PROPERTY_OBJECT_FILE_NAME:
Mike Lockwood7d7fb632010-12-01 18:46:23 -050098 type = MtpConstants.TYPE_STR;
99 break;
100 case MtpConstants.PROPERTY_NAME:
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500101 type = MtpConstants.TYPE_STR;
102 break;
103 case MtpConstants.PROPERTY_DATE_MODIFIED:
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500104 type = MtpConstants.TYPE_STR;
105 break;
106 case MtpConstants.PROPERTY_DATE_ADDED:
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500107 type = MtpConstants.TYPE_STR;
108 break;
109 case MtpConstants.PROPERTY_ORIGINAL_RELEASE_DATE:
110 column = Audio.AudioColumns.YEAR;
111 type = MtpConstants.TYPE_STR;
112 break;
113 case MtpConstants.PROPERTY_PARENT_OBJECT:
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500114 type = MtpConstants.TYPE_UINT32;
115 break;
116 case MtpConstants.PROPERTY_PERSISTENT_UID:
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500117 type = MtpConstants.TYPE_UINT128;
118 break;
119 case MtpConstants.PROPERTY_DURATION:
120 column = Audio.AudioColumns.DURATION;
121 type = MtpConstants.TYPE_UINT32;
122 break;
123 case MtpConstants.PROPERTY_TRACK:
124 column = Audio.AudioColumns.TRACK;
125 type = MtpConstants.TYPE_UINT16;
126 break;
127 case MtpConstants.PROPERTY_DISPLAY_NAME:
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500128 type = MtpConstants.TYPE_STR;
129 break;
130 case MtpConstants.PROPERTY_ARTIST:
131 type = MtpConstants.TYPE_STR;
132 break;
133 case MtpConstants.PROPERTY_ALBUM_NAME:
134 type = MtpConstants.TYPE_STR;
135 break;
136 case MtpConstants.PROPERTY_ALBUM_ARTIST:
137 column = Audio.AudioColumns.ALBUM_ARTIST;
138 type = MtpConstants.TYPE_STR;
139 break;
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500140 case MtpConstants.PROPERTY_COMPOSER:
141 column = Audio.AudioColumns.COMPOSER;
142 type = MtpConstants.TYPE_STR;
143 break;
144 case MtpConstants.PROPERTY_DESCRIPTION:
145 column = Images.ImageColumns.DESCRIPTION;
146 type = MtpConstants.TYPE_STR;
147 break;
Mike Lockwood71827742015-01-23 10:50:08 -0800148 case MtpConstants.PROPERTY_AUDIO_WAVE_CODEC:
149 case MtpConstants.PROPERTY_AUDIO_BITRATE:
150 case MtpConstants.PROPERTY_SAMPLE_RATE:
151 // these are special cased
152 type = MtpConstants.TYPE_UINT32;
153 break;
154 case MtpConstants.PROPERTY_BITRATE_TYPE:
155 case MtpConstants.PROPERTY_NUMBER_OF_CHANNELS:
156 // these are special cased
157 type = MtpConstants.TYPE_UINT16;
158 break;
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500159 default:
160 type = MtpConstants.TYPE_UNDEFINED;
161 Log.e(TAG, "unsupported property " + code);
162 break;
163 }
164
165 if (column != null) {
166 columns.add(column);
167 return new Property(code, type, columns.size() - 1);
168 } else {
169 return new Property(code, type, -1);
170 }
171 }
172
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700173 /**
174 * Gets the values of the properties represented by this property group for the given
175 * object and adds them to the given property list.
176 * @return Response_OK if the operation succeeded.
177 */
178 public int getPropertyList(MtpStorageManager.MtpObject object, MtpPropertyList list) {
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500179 Cursor c = null;
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700180 int id = object.getId();
181 String path = object.getPath().toString();
182 for (Property property : mProperties) {
183 if (property.column != -1 && c == null) {
184 try {
185 // Look up the entry in MediaProvider only if one of those properties is needed.
Jeff Sharkeyff200952019-03-24 12:50:51 -0600186 final Uri uri = MtpDatabase.getObjectPropertiesUri(object.getFormat(),
187 mVolumeName);
188 c = mProvider.query(uri, mColumns,
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700189 PATH_WHERE, new String[] {path}, null, null);
190 if (c != null && !c.moveToNext()) {
191 c.close();
192 c = null;
193 }
Jeff Sharkeyff200952019-03-24 12:50:51 -0600194 } catch (IllegalArgumentException e) {
195 return MtpConstants.RESPONSE_INVALID_OBJECT_PROP_CODE;
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700196 } catch (RemoteException e) {
197 Log.e(TAG, "Mediaprovider lookup failed");
Mike Lockwood4356d812011-02-07 13:40:21 -0500198 }
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500199 }
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700200 switch (property.code) {
201 case MtpConstants.PROPERTY_PROTECTION_STATUS:
202 // protection status is always 0
203 list.append(id, property.code, property.type, 0);
204 break;
205 case MtpConstants.PROPERTY_NAME:
206 case MtpConstants.PROPERTY_OBJECT_FILE_NAME:
207 case MtpConstants.PROPERTY_DISPLAY_NAME:
208 list.append(id, property.code, object.getName());
209 break;
210 case MtpConstants.PROPERTY_DATE_MODIFIED:
211 case MtpConstants.PROPERTY_DATE_ADDED:
212 // convert from seconds to DateTime
213 list.append(id, property.code,
214 format_date_time(object.getModifiedTime()));
215 break;
216 case MtpConstants.PROPERTY_STORAGE_ID:
217 list.append(id, property.code, property.type, object.getStorageId());
218 break;
219 case MtpConstants.PROPERTY_OBJECT_FORMAT:
220 list.append(id, property.code, property.type, object.getFormat());
221 break;
222 case MtpConstants.PROPERTY_OBJECT_SIZE:
223 list.append(id, property.code, property.type, object.getSize());
224 break;
225 case MtpConstants.PROPERTY_PARENT_OBJECT:
226 list.append(id, property.code, property.type,
227 object.getParent().isRoot() ? 0 : object.getParent().getId());
228 break;
229 case MtpConstants.PROPERTY_PERSISTENT_UID:
230 // The persistent uid must be unique and never reused among all objects,
231 // and remain the same between sessions.
232 long puid = (object.getPath().toString().hashCode() << 32)
233 + object.getModifiedTime();
234 list.append(id, property.code, property.type, puid);
235 break;
236 case MtpConstants.PROPERTY_ORIGINAL_RELEASE_DATE:
237 // release date is stored internally as just the year
238 int year = 0;
239 if (c != null)
240 year = c.getInt(property.column);
241 String dateTime = Integer.toString(year) + "0101T000000";
242 list.append(id, property.code, dateTime);
243 break;
244 case MtpConstants.PROPERTY_TRACK:
245 int track = 0;
246 if (c != null)
247 track = c.getInt(property.column);
248 list.append(id, property.code, MtpConstants.TYPE_UINT16,
249 track % 1000);
250 break;
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700251 case MtpConstants.PROPERTY_AUDIO_WAVE_CODEC:
252 case MtpConstants.PROPERTY_AUDIO_BITRATE:
253 case MtpConstants.PROPERTY_SAMPLE_RATE:
254 // we don't have these in our database, so return 0
255 list.append(id, property.code, MtpConstants.TYPE_UINT32, 0);
256 break;
257 case MtpConstants.PROPERTY_BITRATE_TYPE:
258 case MtpConstants.PROPERTY_NUMBER_OF_CHANNELS:
259 // we don't have these in our database, so return 0
260 list.append(id, property.code, MtpConstants.TYPE_UINT16, 0);
261 break;
262 default:
263 switch(property.type) {
264 case MtpConstants.TYPE_UNDEFINED:
265 list.append(id, property.code, property.type, 0);
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500266 break;
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700267 case MtpConstants.TYPE_STR:
268 String value = "";
269 if (c != null)
270 value = c.getString(property.column);
271 list.append(id, property.code, value);
Mike Lockwood71827742015-01-23 10:50:08 -0800272 break;
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500273 default:
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700274 long longValue = 0L;
275 if (c != null)
276 longValue = c.getLong(property.column);
277 list.append(id, property.code, property.type, longValue);
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500278 }
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500279 }
280 }
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700281 if (c != null)
282 c.close();
283 return MtpConstants.RESPONSE_OK;
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500284 }
285
286 private native String format_date_time(long seconds);
287}