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