diff options
| -rw-r--r-- | core/java/android/provider/Mtp.java | 6 | ||||
| -rw-r--r-- | media/java/android/media/MtpCursor.java | 2 | ||||
| -rw-r--r-- | media/mtp/MtpCursor.cpp | 29 | ||||
| -rw-r--r-- | media/mtp/MtpCursor.h | 1 | ||||
| -rw-r--r-- | media/mtp/MtpDataPacket.cpp | 37 | ||||
| -rw-r--r-- | media/mtp/MtpDataPacket.h | 1 | ||||
| -rw-r--r-- | media/mtp/MtpDevice.cpp | 14 | ||||
| -rw-r--r-- | media/mtp/MtpDevice.h | 1 | ||||
| -rw-r--r-- | media/tests/CameraBrowser/res/layout/object_info.xml | 3 | ||||
| -rw-r--r-- | media/tests/CameraBrowser/res/layout/object_list.xml | 33 | ||||
| -rw-r--r-- | media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectBrowser.java | 54 | ||||
| -rw-r--r-- | media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectViewer.java | 18 |
12 files changed, 185 insertions, 14 deletions
diff --git a/core/java/android/provider/Mtp.java b/core/java/android/provider/Mtp.java index ec2698f8975f..3906d230e8cf 100644 --- a/core/java/android/provider/Mtp.java +++ b/core/java/android/provider/Mtp.java @@ -152,6 +152,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> */ diff --git a/media/java/android/media/MtpCursor.java b/media/java/android/media/MtpCursor.java index baf3c12bedb5..cf3bc09db25f 100644 --- a/media/java/android/media/MtpCursor.java +++ b/media/java/android/media/MtpCursor.java @@ -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)); } diff --git a/media/mtp/MtpCursor.cpp b/media/mtp/MtpCursor.cpp index 42d9e38092d9..d63a5bf4d388 100644 --- a/media/mtp/MtpCursor.cpp +++ b/media/mtp/MtpCursor.cpp @@ -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 diff --git a/media/mtp/MtpCursor.h b/media/mtp/MtpCursor.h index 422f0c92e736..d51c0524c61e 100644 --- a/media/mtp/MtpCursor.h +++ b/media/mtp/MtpCursor.h @@ -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 diff --git a/media/mtp/MtpDataPacket.cpp b/media/mtp/MtpDataPacket.cpp index f96284c3182a..d12425aa24a7 100644 --- a/media/mtp/MtpDataPacket.cpp +++ b/media/mtp/MtpDataPacket.cpp @@ -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 diff --git a/media/mtp/MtpDataPacket.h b/media/mtp/MtpDataPacket.h index 4e743b2d64d6..146ef642695e 100644 --- a/media/mtp/MtpDataPacket.h +++ b/media/mtp/MtpDataPacket.h @@ -99,6 +99,7 @@ public: #endif inline bool hasData() const { return mPacketSize > MTP_CONTAINER_HEADER_SIZE; } + void* getData(int& outLength) const; }; }; // namespace android diff --git a/media/mtp/MtpDevice.cpp b/media/mtp/MtpDevice.cpp index 5c39628eedff..ee352174e414 100644 --- a/media/mtp/MtpDevice.cpp +++ b/media/mtp/MtpDevice.cpp @@ -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); diff --git a/media/mtp/MtpDevice.h b/media/mtp/MtpDevice.h index 226b247113b6..0ee930f7dd5b 100644 --- a/media/mtp/MtpDevice.h +++ b/media/mtp/MtpDevice.h @@ -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); diff --git a/media/tests/CameraBrowser/res/layout/object_info.xml b/media/tests/CameraBrowser/res/layout/object_info.xml index f67397fa93f9..c7fd8301c14d 100644 --- a/media/tests/CameraBrowser/res/layout/object_info.xml +++ b/media/tests/CameraBrowser/res/layout/object_info.xml @@ -140,5 +140,8 @@ <TextView android:id="@+id/keywords" style="@style/info_value" /> </TableRow> + <TableRow> + <ImageView android:id="@+id/thumbnail" /> + </TableRow> </TableLayout> diff --git a/media/tests/CameraBrowser/res/layout/object_list.xml b/media/tests/CameraBrowser/res/layout/object_list.xml new file mode 100644 index 000000000000..30c18bb8a077 --- /dev/null +++ b/media/tests/CameraBrowser/res/layout/object_list.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2010 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="horizontal" + android:layout_width="fill_parent" + android:layout_height="fill_parent"> + + <ImageView android:id="@+id/thumbnail" + android:layout_width="wrap_content" + android:layout_height="wrap_content" /> + + <TextView android:id="@+id/name" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceLarge" + android:gravity="center_vertical" + android:paddingLeft="6dip" + android:minHeight="?android:attr/listPreferredItemHeight" /> +</LinearLayout> diff --git a/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectBrowser.java b/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectBrowser.java index da29be830634..019d58457a7c 100644 --- a/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectBrowser.java +++ b/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectBrowser.java @@ -17,16 +17,21 @@ package com.android.camerabrowser; import android.app.ListActivity; +import android.content.Context; import android.content.Intent; import android.database.Cursor; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.net.Uri; import android.os.Bundle; import android.provider.Mtp; import android.util.Log; import android.view.View; import android.widget.ListAdapter; +import android.widget.ImageView; import android.widget.ListView; -import android.widget.SimpleCursorAdapter; +import android.widget.ResourceCursorAdapter; +import android.widget.TextView; /** * A list view displaying all objects within a container (folder or storage unit). @@ -41,7 +46,12 @@ public class ObjectBrowser extends ListActivity { private int mObjectID; private static final String[] OBJECT_COLUMNS = - new String[] { Mtp.Object._ID, Mtp.Object.NAME, Mtp.Object.FORMAT }; + new String[] { Mtp.Object._ID, Mtp.Object.NAME, Mtp.Object.FORMAT, Mtp.Object.THUMB }; + + static final int ID_COLUMN = 0; + static final int NAME_COLUMN = 1; + static final int FORMAT_COLUMN = 2; + static final int THUMB_COLUMN = 3; @Override protected void onCreate(Bundle savedInstanceState) { @@ -70,10 +80,7 @@ public class ObjectBrowser extends ListActivity { startManagingCursor(c); // Map Cursor columns to views defined in simple_list_item_1.xml - mAdapter = new SimpleCursorAdapter(this, - android.R.layout.simple_list_item_1, c, - new String[] { Mtp.Object.NAME }, - new int[] { android.R.id.text1, android.R.id.text2 }); + mAdapter = new ObjectCursorAdapter(this, c); setListAdapter(mAdapter); } } @@ -88,9 +95,9 @@ public class ObjectBrowser extends ListActivity { long format = 0; if (c != null && c.getCount() == 1) { c.moveToFirst(); - long rowId = c.getLong(0); - String name = c.getString(1); - format = c.getLong(2); + long rowId = c.getLong(ID_COLUMN); + String name = c.getString(NAME_COLUMN); + format = c.getLong(FORMAT_COLUMN); Log.d(TAG, "rowId: " + rowId + " name: " + name + " format: " + format); } if (format == Mtp.Object.FORMAT_JFIF) { @@ -107,4 +114,33 @@ public class ObjectBrowser extends ListActivity { startActivity(intent); } } + + private class ObjectCursorAdapter extends ResourceCursorAdapter { + + public ObjectCursorAdapter(Context context, Cursor c) { + super(context, R.layout.object_list, c); + } + + @Override + public void bindView(View view, Context context, Cursor cursor) { + ImageView thumbView = (ImageView)view.findViewById(R.id.thumbnail); + TextView nameView = (TextView)view.findViewById(R.id.name); + + // get the thumbnail + byte[] thumbnail = cursor.getBlob(THUMB_COLUMN); + if (thumbnail != null) { + Bitmap bitmap = BitmapFactory.decodeByteArray(thumbnail, 0, thumbnail.length); + if (bitmap != null) { + thumbView.setImageBitmap(bitmap); + } + } + + // get the name + String name = cursor.getString(NAME_COLUMN); + if (name == null) { + name = ""; + } + nameView.setText(name); + } + } } diff --git a/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectViewer.java b/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectViewer.java index 7055fc566fee..3033c543dc03 100644 --- a/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectViewer.java +++ b/media/tests/CameraBrowser/src/com/android/camerabrowser/ObjectViewer.java @@ -18,11 +18,14 @@ package com.android.camerabrowser; import android.app.Activity; import android.content.Intent; import android.database.Cursor; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.net.Uri; import android.os.Bundle; import android.provider.Mtp; import android.util.Log; import android.view.View; +import android.widget.ImageView; import android.widget.TextView; import java.util.Date; @@ -52,6 +55,7 @@ public class ObjectViewer extends Activity { Mtp.Object.DATE_CREATED, Mtp.Object.DATE_MODIFIED, Mtp.Object.KEYWORDS, + Mtp.Object.THUMB, }; @Override @@ -100,6 +104,20 @@ public class ObjectViewer extends Activity { view.setText(date.toString()); view = (TextView)findViewById(R.id.keywords); view.setText(c.getString(12)); + byte[] thumbnail = c.getBlob(13); + if (thumbnail != null) { + Log.d(TAG, "got thumbnail, length: " + thumbnail.length); + for (int i = 0; i < 50; i++) { + Log.d(TAG, " " + Integer.toHexString(thumbnail[i])); + } + + ImageView thumbView = (ImageView)findViewById(R.id.thumbnail); + Bitmap bitmap = BitmapFactory.decodeByteArray(thumbnail, 0, thumbnail.length); + Log.d(TAG, "bitmap: " + bitmap); + if (bitmap != null) { + thumbView.setImageBitmap(bitmap); + } + } } } } |