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