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