blob: 35d90dcbfd96af812a0404bd33c40f3c0c14502b [file] [log] [blame]
Mike Lockwood5ed68d22010-05-25 19:08:48 -04001/*
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
17#define LOG_TAG "MtpCursor"
Mike Lockwood5ed68d22010-05-25 19:08:48 -040018
Mike Lockwoodb14e5882010-06-29 18:11:52 -040019#include "MtpDebug.h"
Mike Lockwood5ed68d22010-05-25 19:08:48 -040020#include "MtpClient.h"
21#include "MtpCursor.h"
22#include "MtpDevice.h"
23#include "MtpDeviceInfo.h"
24#include "MtpObjectInfo.h"
25#include "MtpStorageInfo.h"
26
Mike Lockwoodb14e5882010-06-29 18:11:52 -040027
Mike Lockwood5ed68d22010-05-25 19:08:48 -040028#include "binder/CursorWindow.h"
29
30namespace android {
31
32/* Device Column IDs */
Mike Lockwood0ef2bf52010-06-08 07:33:14 -040033/* These must match the values in MtpCursor.java */
Mike Lockwood5ed68d22010-05-25 19:08:48 -040034#define DEVICE_ROW_ID 1
35#define DEVICE_MANUFACTURER 2
36#define DEVICE_MODEL 3
37
38/* Storage Column IDs */
Mike Lockwood0ef2bf52010-06-08 07:33:14 -040039/* These must match the values in MtpCursor.java */
Mike Lockwood5ed68d22010-05-25 19:08:48 -040040#define STORAGE_ROW_ID 101
41#define STORAGE_IDENTIFIER 102
42#define STORAGE_DESCRIPTION 103
43
44/* Object Column IDs */
Mike Lockwood0ef2bf52010-06-08 07:33:14 -040045/* These must match the values in MtpCursor.java */
46#define OBJECT_ROW_ID 201
47#define OBJECT_STORAGE_ID 202
48#define OBJECT_FORMAT 203
49#define OBJECT_PROTECTION_STATUS 204
50#define OBJECT_SIZE 205
51#define OBJECT_THUMB_FORMAT 206
52#define OBJECT_THUMB_SIZE 207
53#define OBJECT_THUMB_WIDTH 208
54#define OBJECT_THUMB_HEIGHT 209
55#define OBJECT_IMAGE_WIDTH 210
56#define OBJECT_IMAGE_HEIGHT 211
57#define OBJECT_IMAGE_DEPTH 212
58#define OBJECT_PARENT 213
59#define OBJECT_ASSOCIATION_TYPE 214
60#define OBJECT_ASSOCIATION_DESC 215
61#define OBJECT_SEQUENCE_NUMBER 216
62#define OBJECT_NAME 217
63#define OBJECT_DATE_CREATED 218
64#define OBJECT_DATE_MODIFIED 219
65#define OBJECT_KEYWORDS 220
Mike Lockwood3e072b32010-06-10 16:34:20 -040066#define OBJECT_THUMB 221
Mike Lockwood5ed68d22010-05-25 19:08:48 -040067
68MtpCursor::MtpCursor(MtpClient* client, int queryType, int deviceID,
Mike Lockwood4620df72010-09-23 14:01:11 -040069 MtpStorageID storageID, MtpObjectHandle objectID,
70 int columnCount, int* columns)
Mike Lockwood5ed68d22010-05-25 19:08:48 -040071 : mClient(client),
72 mQueryType(queryType),
73 mDeviceID(deviceID),
74 mStorageID(storageID),
75 mQbjectID(objectID),
76 mColumnCount(columnCount),
77 mColumns(NULL)
78{
79 if (columns) {
80 mColumns = new int[columnCount];
81 memcpy(mColumns, columns, columnCount * sizeof(int));
82 }
83}
84
85MtpCursor::~MtpCursor() {
86 delete[] mColumns;
87}
88
89int MtpCursor::fillWindow(CursorWindow* window, int startPos) {
90 LOGD("MtpCursor::fillWindow mQueryType: %d\n", mQueryType);
91
92 switch (mQueryType) {
93 case DEVICE:
94 return fillDevices(window, startPos);
95 case DEVICE_ID:
96 return fillDevice(window, startPos);
97 case STORAGE:
98 return fillStorages(window, startPos);
99 case STORAGE_ID:
100 return fillStorage(window, startPos);
101 case OBJECT:
102 return fillObjects(window, 0, startPos);
103 case OBJECT_ID:
104 return fillObject(window, startPos);
105 case STORAGE_CHILDREN:
106 return fillObjects(window, -1, startPos);
107 case OBJECT_CHILDREN:
108 return fillObjects(window, mQbjectID, startPos);
109 default:
110 LOGE("MtpCursor::fillWindow: unknown query type %d\n", mQueryType);
111 return 0;
112 }
113}
114
115int MtpCursor::fillDevices(CursorWindow* window, int startPos) {
116 int count = 0;
117 MtpDeviceList& deviceList = mClient->getDeviceList();
118 for (int i = 0; i < deviceList.size(); i++) {
119 MtpDevice* device = deviceList[i];
120 if (fillDevice(window, device, startPos)) {
121 count++;
122 startPos++;
123 } else {
124 break;
125 }
126 }
127 return count;
128}
129
130int MtpCursor::fillDevice(CursorWindow* window, int startPos) {
131 MtpDevice* device = mClient->getDevice(mDeviceID);
132 if (device && fillDevice(window, device, startPos))
133 return 1;
134 else
135 return 0;
136}
137
138int MtpCursor::fillStorages(CursorWindow* window, int startPos) {
139 int count = 0;
140 MtpDevice* device = mClient->getDevice(mDeviceID);
141 if (!device)
142 return 0;
143 MtpStorageIDList* storageIDs = device->getStorageIDs();
144 if (!storageIDs)
145 return 0;
146
147 for (int i = 0; i < storageIDs->size(); i++) {
148 MtpStorageID storageID = (*storageIDs)[i];
149 if (fillStorage(window, device, storageID, startPos)) {
150 count++;
151 startPos++;
152 } else {
153 break;
154 }
155 }
156 delete storageIDs;
157 return count;
158}
159
160int MtpCursor::fillStorage(CursorWindow* window, int startPos) {
161 MtpDevice* device = mClient->getDevice(mDeviceID);
162 if (device && fillStorage(window, device, mStorageID, startPos))
163 return 1;
164 else
165 return 0;
166}
167
168int MtpCursor::fillObjects(CursorWindow* window, int parent, int startPos) {
169 int count = 0;
170 MtpDevice* device = mClient->getDevice(mDeviceID);
171 if (!device)
172 return 0;
173 MtpObjectHandleList* handles = device->getObjectHandles(mStorageID, 0, parent);
174 if (!handles)
175 return 0;
176
177 for (int i = 0; i < handles->size(); i++) {
178 MtpObjectHandle handle = (*handles)[i];
179 if (fillObject(window, device, handle, startPos)) {
180 count++;
181 startPos++;
182 } else {
183 break;
184 }
185 }
186 delete handles;
187 return count;
188}
189
190int MtpCursor::fillObject(CursorWindow* window, int startPos) {
191 MtpDevice* device = mClient->getDevice(mDeviceID);
192 if (device && fillObject(window, device, mQbjectID, startPos))
193 return 1;
194 else
195 return 0;
196}
197
198bool MtpCursor::fillDevice(CursorWindow* window, MtpDevice* device, int row) {
199 MtpDeviceInfo* deviceInfo = device->getDeviceInfo();
200 if (!deviceInfo)
201 return false;
202 if (!prepareRow(window))
203 return false;
204
205 for (int i = 0; i < mColumnCount; i++) {
206 switch (mColumns[i]) {
207 case DEVICE_ROW_ID:
208 if (!putLong(window, device->getID(), row, i))
209 return false;
210 break;
211 case DEVICE_MANUFACTURER:
212 if (!putString(window, deviceInfo->mManufacturer, row, i))
213 return false;
214 break;
215 case DEVICE_MODEL:
216 if (!putString(window, deviceInfo->mModel, row, i))
217 return false;
218 break;
219 default:
220 LOGE("fillDevice: unknown column %d\n", mColumns[i]);
221 return false;
222 }
223 }
224
225 return true;
226}
227
228bool MtpCursor::fillStorage(CursorWindow* window, MtpDevice* device,
229 MtpStorageID storageID, int row) {
230
231LOGD("fillStorage %d\n", storageID);
232
233 MtpStorageInfo* storageInfo = device->getStorageInfo(storageID);
234 if (!storageInfo)
235 return false;
236 if (!prepareRow(window)) {
237 delete storageInfo;
238 return false;
239 }
240
241 const char* text;
242 for (int i = 0; i < mColumnCount; i++) {
243 switch (mColumns[i]) {
244 case STORAGE_ROW_ID:
245 if (!putLong(window, storageID, row, i))
246 goto fail;
247 break;
248 case STORAGE_IDENTIFIER:
249 text = storageInfo->mVolumeIdentifier;
250 if (!text || !text[0])
251 text = "Camera Storage";
252 if (!putString(window, text, row, i))
253 goto fail;
254 break;
255 case STORAGE_DESCRIPTION:
256 text = storageInfo->mStorageDescription;
257 if (!text || !text[0])
258 text = "Storage Description";
259 if (!putString(window, text, row, i))
260 goto fail;
261 break;
262 default:
263 LOGE("fillStorage: unknown column %d\n", mColumns[i]);
264 goto fail;
265 }
266 }
267
268 delete storageInfo;
269 return true;
270
271fail:
272 delete storageInfo;
273 return false;
274}
275
276bool MtpCursor::fillObject(CursorWindow* window, MtpDevice* device,
277 MtpObjectHandle objectID, int row) {
278
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400279 MtpObjectInfo* objectInfo = device->getObjectInfo(objectID);
280 if (!objectInfo)
281 return false;
Mike Lockwood0ef2bf52010-06-08 07:33:14 -0400282 // objectInfo->print();
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400283 if (!prepareRow(window)) {
284 delete objectInfo;
285 return false;
286 }
287
288 for (int i = 0; i < mColumnCount; i++) {
289 switch (mColumns[i]) {
290 case OBJECT_ROW_ID:
291 if (!putLong(window, objectID, row, i))
292 goto fail;
293 break;
Mike Lockwood0ef2bf52010-06-08 07:33:14 -0400294 case OBJECT_STORAGE_ID:
295 if (!putLong(window, objectInfo->mStorageID, row, i))
296 goto fail;
297 break;
298 case OBJECT_FORMAT:
299 if (!putLong(window, objectInfo->mFormat, row, i))
300 goto fail;
301 break;
302 case OBJECT_PROTECTION_STATUS:
303 if (!putLong(window, objectInfo->mProtectionStatus, row, i))
304 goto fail;
305 break;
306 case OBJECT_SIZE:
307 if (!putLong(window, objectInfo->mCompressedSize, row, i))
308 goto fail;
309 break;
310 case OBJECT_THUMB_FORMAT:
311 if (!putLong(window, objectInfo->mThumbFormat, row, i))
312 goto fail;
313 break;
314 case OBJECT_THUMB_SIZE:
315 if (!putLong(window, objectInfo->mThumbCompressedSize, row, i))
316 goto fail;
317 break;
318 case OBJECT_THUMB_WIDTH:
319 if (!putLong(window, objectInfo->mThumbPixWidth, row, i))
320 goto fail;
321 break;
322 case OBJECT_THUMB_HEIGHT:
323 if (!putLong(window, objectInfo->mThumbPixHeight, row, i))
324 goto fail;
325 break;
326 case OBJECT_IMAGE_WIDTH:
327 if (!putLong(window, objectInfo->mImagePixWidth, row, i))
328 goto fail;
329 break;
330 case OBJECT_IMAGE_HEIGHT:
331 if (!putLong(window, objectInfo->mImagePixHeight, row, i))
332 goto fail;
333 break;
334 case OBJECT_IMAGE_DEPTH:
335 if (!putLong(window, objectInfo->mImagePixDepth, row, i))
336 goto fail;
337 break;
338 case OBJECT_PARENT:
339 if (!putLong(window, objectInfo->mParent, row, i))
340 goto fail;
341 break;
342 case OBJECT_ASSOCIATION_TYPE:
343 if (!putLong(window, objectInfo->mAssociationType, row, i))
344 goto fail;
345 break;
346 case OBJECT_ASSOCIATION_DESC:
347 if (!putLong(window, objectInfo->mAssociationDesc, row, i))
348 goto fail;
349 break;
350 case OBJECT_SEQUENCE_NUMBER:
351 if (!putLong(window, objectInfo->mSequenceNumber, row, i))
352 goto fail;
353 break;
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400354 case OBJECT_NAME:
355 if (!putString(window, objectInfo->mName, row, i))
356 goto fail;
357 break;
Mike Lockwood0ef2bf52010-06-08 07:33:14 -0400358 case OBJECT_DATE_CREATED:
359 if (!putLong(window, objectInfo->mDateCreated, row, i))
360 goto fail;
361 break;
362 case OBJECT_DATE_MODIFIED:
363 if (!putLong(window, objectInfo->mDateModified, row, i))
364 goto fail;
365 break;
366 case OBJECT_KEYWORDS:
367 if (!putString(window, objectInfo->mKeywords, row, i))
368 goto fail;
369 break;
Mike Lockwood3e072b32010-06-10 16:34:20 -0400370 case OBJECT_THUMB:
Mike Lockwood2b6c4a22010-07-26 20:35:21 -0400371 if (!putThumbnail(window, objectID, objectInfo->mFormat, row, i))
Mike Lockwood3e072b32010-06-10 16:34:20 -0400372 goto fail;
373 break;
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400374 default:
Mike Lockwood32eaa262010-09-20 18:23:21 -0400375 LOGE("fillObject: unknown column %d\n", mColumns[i]);
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400376 goto fail;
377 }
378 }
379
Mike Lockwood0ef2bf52010-06-08 07:33:14 -0400380 delete objectInfo;
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400381 return true;
382
383fail:
384 delete objectInfo;
385 return false;
386}
387
388bool MtpCursor::prepareRow(CursorWindow* window) {
389 if (!window->setNumColumns(mColumnCount)) {
390 LOGE("Failed to change column count from %d to %d", window->getNumColumns(), mColumnCount);
391 return false;
392 }
393 field_slot_t * fieldDir = window->allocRow();
394 if (!fieldDir) {
395 LOGE("Failed allocating fieldDir");
396 return false;
397 }
398 return true;
399}
400
401
Mike Lockwood3a2f37f2010-09-28 09:14:50 -0400402bool MtpCursor::putLong(CursorWindow* window, int64_t value, int row, int column) {
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400403 if (!window->putLong(row, column, value)) {
404 window->freeLastRow();
405 LOGE("Failed allocating space for a long in column %d", column);
406 return false;
407 }
408 return true;
409}
410
411bool MtpCursor::putString(CursorWindow* window, const char* text, int row, int column) {
412 int size = strlen(text) + 1;
413 int offset = window->alloc(size);
414 if (!offset) {
415 window->freeLastRow();
416 LOGE("Failed allocating %u bytes for text/blob %s", size, text);
417 return false;
418 }
419 window->copyIn(offset, (const uint8_t*)text, size);
420
421 // This must be updated after the call to alloc(), since that
422 // may move the field around in the window
423 field_slot_t * fieldSlot = window->getFieldSlot(row, column);
424 fieldSlot->type = FIELD_TYPE_STRING;
425 fieldSlot->data.buffer.offset = offset;
426 fieldSlot->data.buffer.size = size;
427 return true;
428}
429
Mike Lockwood4620df72010-09-23 14:01:11 -0400430bool MtpCursor::putThumbnail(CursorWindow* window, MtpObjectHandle objectID,
431 MtpObjectFormat format, int row, int column) {
Mike Lockwood3e072b32010-06-10 16:34:20 -0400432 MtpDevice* device = mClient->getDevice(mDeviceID);
Mike Lockwood2b6c4a22010-07-26 20:35:21 -0400433 void* thumbnail;
434 int size, offset;
435 if (format == MTP_FORMAT_ASSOCIATION) {
436 thumbnail = NULL;
437 size = offset = 0;
438 } else {
439 thumbnail = device->getThumbnail(objectID, size);
Mike Lockwood3e072b32010-06-10 16:34:20 -0400440
Mike Lockwoodf43c6412010-07-27 11:50:34 -0400441 LOGV("putThumbnail: %p, size: %d\n", thumbnail, size);
Mike Lockwood2b6c4a22010-07-26 20:35:21 -0400442 offset = window->alloc(size);
443 if (!offset) {
444 window->freeLastRow();
445 LOGE("Failed allocating %u bytes for thumbnail", size);
446 return false;
447 }
Mike Lockwood3e072b32010-06-10 16:34:20 -0400448 }
Mike Lockwood2b6c4a22010-07-26 20:35:21 -0400449 if (thumbnail)
Mike Lockwood3e072b32010-06-10 16:34:20 -0400450 window->copyIn(offset, (const uint8_t*)thumbnail, size);
451
452 // This must be updated after the call to alloc(), since that
453 // may move the field around in the window
454 field_slot_t * fieldSlot = window->getFieldSlot(row, column);
455 fieldSlot->type = FIELD_TYPE_BLOB;
456 fieldSlot->data.buffer.offset = offset;
457 fieldSlot->data.buffer.size = size;
458 return true;
459}
460
Mike Lockwood5ed68d22010-05-25 19:08:48 -0400461} // namespace android