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" |
| 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 | |
| 29 | namespace android { |
| 30 | |
| 31 | /* Device Column IDs */ |
Mike Lockwood | 0ef2bf5 | 2010-06-08 07:33:14 -0400 | [diff] [blame] | 32 | /* These must match the values in MtpCursor.java */ |
Mike Lockwood | 5ed68d2 | 2010-05-25 19:08:48 -0400 | [diff] [blame] | 33 | #define DEVICE_ROW_ID 1 |
| 34 | #define DEVICE_MANUFACTURER 2 |
| 35 | #define DEVICE_MODEL 3 |
| 36 | |
| 37 | /* Storage Column IDs */ |
Mike Lockwood | 0ef2bf5 | 2010-06-08 07:33:14 -0400 | [diff] [blame] | 38 | /* These must match the values in MtpCursor.java */ |
Mike Lockwood | 5ed68d2 | 2010-05-25 19:08:48 -0400 | [diff] [blame] | 39 | #define STORAGE_ROW_ID 101 |
| 40 | #define STORAGE_IDENTIFIER 102 |
| 41 | #define STORAGE_DESCRIPTION 103 |
| 42 | |
| 43 | /* Object Column IDs */ |
Mike Lockwood | 0ef2bf5 | 2010-06-08 07:33:14 -0400 | [diff] [blame] | 44 | /* 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 Lockwood | 5ed68d2 | 2010-05-25 19:08:48 -0400 | [diff] [blame] | 65 | |
| 66 | MtpCursor::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 | |
| 82 | MtpCursor::~MtpCursor() { |
| 83 | delete[] mColumns; |
| 84 | } |
| 85 | |
| 86 | int 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 | |
| 112 | int 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 | |
| 127 | int 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 | |
| 135 | int 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 | |
| 157 | int 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 | |
| 165 | int 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 | |
| 187 | int 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 | |
| 195 | bool 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 | |
| 225 | bool MtpCursor::fillStorage(CursorWindow* window, MtpDevice* device, |
| 226 | MtpStorageID storageID, int row) { |
| 227 | |
| 228 | LOGD("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 | |
| 268 | fail: |
| 269 | delete storageInfo; |
| 270 | return false; |
| 271 | } |
| 272 | |
| 273 | bool MtpCursor::fillObject(CursorWindow* window, MtpDevice* device, |
| 274 | MtpObjectHandle objectID, int row) { |
| 275 | |
Mike Lockwood | 5ed68d2 | 2010-05-25 19:08:48 -0400 | [diff] [blame] | 276 | MtpObjectInfo* objectInfo = device->getObjectInfo(objectID); |
| 277 | if (!objectInfo) |
| 278 | return false; |
Mike Lockwood | 0ef2bf5 | 2010-06-08 07:33:14 -0400 | [diff] [blame] | 279 | // objectInfo->print(); |
Mike Lockwood | 5ed68d2 | 2010-05-25 19:08:48 -0400 | [diff] [blame] | 280 | 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 Lockwood | 0ef2bf5 | 2010-06-08 07:33:14 -0400 | [diff] [blame] | 291 | 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 Lockwood | 5ed68d2 | 2010-05-25 19:08:48 -0400 | [diff] [blame] | 351 | case OBJECT_NAME: |
| 352 | if (!putString(window, objectInfo->mName, row, i)) |
| 353 | goto fail; |
| 354 | break; |
Mike Lockwood | 0ef2bf5 | 2010-06-08 07:33:14 -0400 | [diff] [blame] | 355 | 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 Lockwood | 5ed68d2 | 2010-05-25 19:08:48 -0400 | [diff] [blame] | 367 | default: |
| 368 | LOGE("fillStorage: unknown column %d\n", mColumns[i]); |
| 369 | goto fail; |
| 370 | } |
| 371 | } |
| 372 | |
Mike Lockwood | 0ef2bf5 | 2010-06-08 07:33:14 -0400 | [diff] [blame] | 373 | delete objectInfo; |
Mike Lockwood | 5ed68d2 | 2010-05-25 19:08:48 -0400 | [diff] [blame] | 374 | return true; |
| 375 | |
| 376 | fail: |
| 377 | delete objectInfo; |
| 378 | return false; |
| 379 | } |
| 380 | |
| 381 | bool 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 | |
| 395 | bool 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 | |
| 405 | bool 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 |