MTP: Add support for retrieving thumbnails to MTP content provider.

Signed-off-by: Mike Lockwood <lockwood@android.com>
This commit is contained in:
Mike Lockwood
2010-06-10 16:34:20 -04:00
parent a9aaf8ffce
commit dda5686092
8 changed files with 86 additions and 5 deletions

View File

@@ -151,6 +151,12 @@ public final class Mtp
*/
public static final String THUMB_HEIGHT = "thumb_height";
/**
* The object's thumbnail.
* <P>Type: BLOB</P>
*/
public static final String THUMB = "thumb";
/**
* The width of the object in pixels.
* <P>Type: INTEGER</P>

View File

@@ -159,6 +159,7 @@ public final class MtpCursor extends AbstractWindowedCursor {
private static final int OBJECT_DATE_CREATED = 218;
private static final int OBJECT_DATE_MODIFIED = 219;
private static final int OBJECT_KEYWORDS = 220;
private static final int OBJECT_THUMB = 221;
private static HashMap<String, Integer> sDeviceProjectionMap;
private static HashMap<String, Integer> sStorageProjectionMap;
@@ -196,6 +197,7 @@ public final class MtpCursor extends AbstractWindowedCursor {
sObjectProjectionMap.put(Mtp.Object.DATE_CREATED, new Integer(OBJECT_DATE_CREATED));
sObjectProjectionMap.put(Mtp.Object.DATE_MODIFIED, new Integer(OBJECT_DATE_MODIFIED));
sObjectProjectionMap.put(Mtp.Object.KEYWORDS, new Integer(OBJECT_KEYWORDS));
sObjectProjectionMap.put(Mtp.Object.THUMB, new Integer(OBJECT_THUMB));
sObjectProjectionMap.put(Mtp.Object.NAME, new Integer(OBJECT_NAME));
}

View File

@@ -62,6 +62,7 @@ namespace android {
#define OBJECT_DATE_CREATED 218
#define OBJECT_DATE_MODIFIED 219
#define OBJECT_KEYWORDS 220
#define OBJECT_THUMB 221
MtpCursor::MtpCursor(MtpClient* client, int queryType, int deviceID,
int storageID, int objectID, int columnCount, int* columns)
@@ -364,6 +365,10 @@ bool MtpCursor::fillObject(CursorWindow* window, MtpDevice* device,
if (!putString(window, objectInfo->mKeywords, row, i))
goto fail;
break;
case OBJECT_THUMB:
if (!putThumbnail(window, objectID, row, i))
goto fail;
break;
default:
LOGE("fillStorage: unknown column %d\n", mColumns[i]);
goto fail;
@@ -421,4 +426,28 @@ bool MtpCursor::putString(CursorWindow* window, const char* text, int row, int c
return true;
}
bool MtpCursor::putThumbnail(CursorWindow* window, int objectID, int row, int column) {
MtpDevice* device = mClient->getDevice(mDeviceID);
int size;
void* thumbnail = device->getThumbnail(objectID, size);
LOGD("putThumbnail: %p, size: %d\n", thumbnail, size);
int offset = window->alloc(size);
if (!offset) {
window->freeLastRow();
LOGE("Failed allocating %u bytes for thumbnail", size);
return false;
}
if (size > 0)
window->copyIn(offset, (const uint8_t*)thumbnail, size);
// This must be updated after the call to alloc(), since that
// may move the field around in the window
field_slot_t * fieldSlot = window->getFieldSlot(row, column);
fieldSlot->type = FIELD_TYPE_BLOB;
fieldSlot->data.buffer.offset = offset;
fieldSlot->data.buffer.size = size;
return true;
}
} // namespace android

View File

@@ -68,6 +68,7 @@ private:
bool prepareRow(CursorWindow* window);
bool putLong(CursorWindow* window, int value, int row, int column);
bool putString(CursorWindow* window, const char* text, int row, int column);
bool putThumbnail(CursorWindow* window, int objectID, int row, int column);
};
}; // namespace android

View File

@@ -361,11 +361,24 @@ int MtpDataPacket::writeDataHeader(int fd, uint32_t length) {
#ifdef MTP_HOST
int MtpDataPacket::read(struct usb_endpoint *ep) {
// first read the header
int ret = transfer(ep, mBuffer, mBufferSize);
printf("MtpDataPacket::transfer returned %d\n", ret);
if (ret >= 0)
mPacketSize = ret;
return ret;
int length = transfer(ep, mBuffer, mBufferSize);
if (length > MTP_CONTAINER_HEADER_SIZE) {
// look at the length field to see if the data spans multiple packets
uint32_t totalLength = MtpPacket::getUInt32(MTP_CONTAINER_LENGTH_OFFSET);
while (totalLength > length) {
allocate(length + mAllocationIncrement);
int ret = transfer(ep, mBuffer + length, mAllocationIncrement);
if (ret >= 0)
length += ret;
else {
length = ret;
break;
}
}
}
if (length >= 0)
mPacketSize = length;
return length;
}
int MtpDataPacket::write(struct usb_endpoint *ep) {
@@ -382,4 +395,18 @@ int MtpDataPacket::write(struct usb_endpoint *ep) {
#endif // MTP_HOST
void* MtpDataPacket::getData(int& outLength) const {
int length = mPacketSize - MTP_CONTAINER_HEADER_SIZE;
if (length > 0) {
void* result = malloc(length);
if (result) {
memcpy(result, mBuffer + MTP_CONTAINER_HEADER_SIZE, length);
outLength = length;
return result;
}
}
outLength = 0;
return NULL;
}
} // namespace android

View File

@@ -99,6 +99,7 @@ public:
#endif
inline bool hasData() const { return mPacketSize > MTP_CONTAINER_HEADER_SIZE; }
void* getData(int& outLength) const;
};
}; // namespace android

View File

@@ -194,6 +194,20 @@ MtpObjectInfo* MtpDevice::getObjectInfo(MtpObjectHandle handle) {
return NULL;
}
void* MtpDevice::getThumbnail(MtpObjectHandle handle, int& outLength) {
mRequest.reset();
mRequest.setParameter(1, handle);
if (sendRequest(MTP_OPERATION_GET_THUMB) && readData()) {
MtpResponseCode ret = readResponse();
if (ret == MTP_RESPONSE_OK) {
return mData.getData(outLength);
}
}
outLength = 0;
return NULL;
}
MtpProperty* MtpDevice::getDevicePropDesc(MtpDeviceProperty code) {
mRequest.reset();
mRequest.setParameter(1, code);

View File

@@ -70,6 +70,7 @@ public:
MtpStorageInfo* getStorageInfo(MtpStorageID storageID);
MtpObjectHandleList* getObjectHandles(MtpStorageID storageID, MtpObjectFormat format, MtpObjectHandle parent);
MtpObjectInfo* getObjectInfo(MtpObjectHandle handle);
void* getThumbnail(MtpObjectHandle handle, int& outLength);
MtpProperty* getDevicePropDesc(MtpDeviceProperty code);