PTP host: Implement getObjectHandles and getObjectInfo commands

Change-Id: I3ff6e52237f400b4e50c534a1f964c80789bfe98
Signed-off-by: Mike Lockwood <lockwood@android.com>
diff --git a/media/mtp/Android.mk b/media/mtp/Android.mk
index 2395ccb..d9c69a4 100644
--- a/media/mtp/Android.mk
+++ b/media/mtp/Android.mk
@@ -58,11 +58,13 @@
                   MtpDataPacket.cpp                     \
                   MtpDebug.cpp                          \
                   MtpDeviceInfo.cpp                     \
+                  MtpObjectInfo.cpp                     \
                   MtpPacket.cpp                         \
                   MtpRequestPacket.cpp                  \
                   MtpResponsePacket.cpp                 \
                   MtpStorageInfo.cpp                    \
                   MtpStringBuffer.cpp                   \
+                  MtpUtils.cpp                          \
                   ../../libs/utils/VectorImpl.cpp       \
                   ../../libs/utils/SharedBuffer.cpp     \
 
diff --git a/media/mtp/MtpClient.cpp b/media/mtp/MtpClient.cpp
index 73234b1..de3c199 100644
--- a/media/mtp/MtpClient.cpp
+++ b/media/mtp/MtpClient.cpp
@@ -27,6 +27,7 @@
 #include "MtpClient.h"
 #include "MtpDebug.h"
 #include "MtpDeviceInfo.h"
+#include "MtpObjectInfo.h"
 #include "MtpStorageInfo.h"
 #include "MtpStringBuffer.h"
 
@@ -46,7 +47,6 @@
 MtpClient::~MtpClient() {
 }
 
-
 bool MtpClient::openSession() {
 printf("openSession\n");
     mSessionID = 0;
@@ -118,6 +118,41 @@
     return NULL;
 }
 
+MtpObjectHandleList* MtpClient::getObjectHandles(MtpStorageID storageID,
+            MtpObjectFormat format, MtpObjectHandle parent) {
+    mRequest.reset();
+    mRequest.setParameter(1, storageID);
+    mRequest.setParameter(2, format);
+    mRequest.setParameter(3, parent);
+    if (!sendRequest(MTP_OPERATION_GET_OBJECT_HANDLES))
+        return NULL;
+    if (!readData())
+        return NULL;
+    MtpResponseCode ret = readResponse();
+printf("getObjectHandles returned %04X\n", ret);
+    if (ret == MTP_RESPONSE_OK) {
+        return mData.getAUInt32();
+    }
+    return NULL;
+}
+
+MtpObjectInfo* MtpClient::getObjectInfo(MtpObjectHandle handle) {
+    mRequest.reset();
+    mRequest.setParameter(1, handle);
+    if (!sendRequest(MTP_OPERATION_GET_OBJECT_INFO))
+        return NULL;
+    if (!readData())
+        return NULL;
+    MtpResponseCode ret = readResponse();
+printf("getObjectInfo returned %04X\n", ret);
+    if (ret == MTP_RESPONSE_OK) {
+        MtpObjectInfo* info = new MtpObjectInfo(handle);
+        info->read(mData);
+        return info;
+    }
+    return NULL;
+}
+
 bool MtpClient::sendRequest(MtpOperationCode operation) {
     printf("sendRequest: %s\n", MtpDebug::getOperationCodeName(operation));
     mRequest.setOperationCode(operation);
diff --git a/media/mtp/MtpClient.h b/media/mtp/MtpClient.h
index b43a9e0..76d9648 100644
--- a/media/mtp/MtpClient.h
+++ b/media/mtp/MtpClient.h
@@ -25,40 +25,43 @@
 namespace android {
 
 class MtpDeviceInfo;
+class MtpObjectInfo;
 class MtpStorageInfo;
 
 class MtpClient {
 private:
-    struct usb_endpoint *mEndpointIn;
-    struct usb_endpoint *mEndpointOut;
-    struct usb_endpoint *mEndpointIntr;
+    struct usb_endpoint*    mEndpointIn;
+    struct usb_endpoint*    mEndpointOut;
+    struct usb_endpoint*    mEndpointIntr;
 
     // current session ID
-    MtpSessionID        mSessionID;
+    MtpSessionID            mSessionID;
     // current transaction ID
-    MtpTransactionID    mTransactionID;
+    MtpTransactionID        mTransactionID;
 
-    MtpRequestPacket    mRequest;
-    MtpDataPacket       mData;
-    MtpResponsePacket   mResponse;
+    MtpRequestPacket        mRequest;
+    MtpDataPacket           mData;
+    MtpResponsePacket       mResponse;
 
 public:
-                        MtpClient(struct usb_endpoint *ep_in, struct usb_endpoint *ep_out,
+                            MtpClient(struct usb_endpoint *ep_in, struct usb_endpoint *ep_out,
                                     struct usb_endpoint *ep_intr);
-    virtual             ~MtpClient();
+    virtual                 ~MtpClient();
 
-    bool                openSession();
-    bool                closeSession();
+    bool                    openSession();
+    bool                    closeSession();
 
-    MtpDeviceInfo*      getDeviceInfo();
-    MtpStorageIDList*   getStorageIDs();
-    MtpStorageInfo*     getStorageInfo(MtpStorageID storageID);
+    MtpDeviceInfo*          getDeviceInfo();
+    MtpStorageIDList*       getStorageIDs();
+    MtpStorageInfo*         getStorageInfo(MtpStorageID storageID);
+    MtpObjectHandleList*    getObjectHandles(MtpStorageID storageID, MtpObjectFormat format, MtpObjectHandle parent);
+    MtpObjectInfo*          getObjectInfo(MtpObjectHandle handle);
 
 private:
-    bool                sendRequest(MtpOperationCode operation);
-    bool                sendData(MtpOperationCode operation);
-    bool                readData();
-    MtpResponseCode     readResponse();
+    bool                    sendRequest(MtpOperationCode operation);
+    bool                    sendData(MtpOperationCode operation);
+    bool                    readData();
+    MtpResponseCode         readResponse();
 
 };
 
diff --git a/media/mtp/MtpObjectInfo.cpp b/media/mtp/MtpObjectInfo.cpp
new file mode 100644
index 0000000..8ca2880
--- /dev/null
+++ b/media/mtp/MtpObjectInfo.cpp
@@ -0,0 +1,96 @@
+/*
+ * 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.
+ */
+
+#include <stdlib.h>
+
+#include "MtpDataPacket.h"
+#include "MtpObjectInfo.h"
+#include "MtpStringBuffer.h"
+#include "MtpUtils.h"
+
+namespace android {
+
+MtpObjectInfo::MtpObjectInfo(MtpObjectHandle handle)
+    :   mHandle(handle),
+        mStorageID(0),
+        mFormat(0),
+        mProtectionStatus(0),
+        mCompressedSize(0),
+        mThumbFormat(0),
+        mThumbCompressedSize(0),
+        mThumbPixWidth(0),
+        mThumbPixHeight(0),
+        mImagePixWidth(0),
+        mImagePixHeight(0),
+        mImagePixDepth(0),
+        mParent(0),
+        mAssociationType(0),
+        mAssociationDesc(0),
+        mSequenceNumber(0),
+        mName(NULL),
+        mDateCreated(0),
+        mDateModified(0),
+        mKeywords(NULL)
+{
+}
+
+MtpObjectInfo::~MtpObjectInfo() {
+    if (mName)
+        free(mName);
+    if (mKeywords)
+        free(mKeywords);
+}
+
+void MtpObjectInfo::read(MtpDataPacket& packet) {
+    MtpStringBuffer string;
+    time_t time;
+
+    mStorageID = packet.getUInt32();
+    mFormat = packet.getUInt16();
+    mProtectionStatus = packet.getUInt16();
+    mCompressedSize = packet.getUInt32();
+    mThumbFormat = packet.getUInt16();
+    mCompressedSize = packet.getUInt32();
+    mThumbPixWidth = packet.getUInt32();
+    mThumbPixHeight = packet.getUInt32();
+    mImagePixWidth = packet.getUInt32();
+    mImagePixHeight = packet.getUInt32();
+    mImagePixDepth = packet.getUInt32();
+    mParent = packet.getUInt32();
+    mAssociationType = packet.getUInt16();
+    mAssociationDesc = packet.getUInt32();
+    mSequenceNumber = packet.getUInt32();
+
+    packet.getString(string);
+    mName = strdup((const char *)string);
+
+    packet.getString(string);
+    if (parseDateTime((const char*)string, time))
+        mDateCreated = time;
+
+    packet.getString(string);
+    if (parseDateTime((const char*)string, time))
+        mDateModified = time;
+
+    packet.getString(string);
+    mKeywords = strdup((const char *)string);
+}
+
+void MtpObjectInfo::print() {
+    printf("MtpObject Info %08X: %s\n", mHandle, mName);
+}
+
+}  // namespace android
diff --git a/media/mtp/MtpObjectInfo.h b/media/mtp/MtpObjectInfo.h
new file mode 100644
index 0000000..c7a449c
--- /dev/null
+++ b/media/mtp/MtpObjectInfo.h
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+#ifndef _MTP_OBJECT_INFO_H
+#define _MTP_OBJECT_INFO_H
+
+#include "MtpTypes.h"
+
+namespace android {
+
+class MtpDataPacket;
+
+class MtpObjectInfo {
+public:
+    MtpObjectHandle     mHandle;
+    MtpStorageID        mStorageID;
+    MtpObjectFormat     mFormat;
+    uint16_t            mProtectionStatus;
+    uint32_t            mCompressedSize;
+    MtpObjectFormat     mThumbFormat;
+    uint32_t            mThumbCompressedSize;
+    uint32_t            mThumbPixWidth;
+    uint32_t            mThumbPixHeight;
+    uint32_t            mImagePixWidth;
+    uint32_t            mImagePixHeight;
+    uint32_t            mImagePixDepth;
+    MtpObjectHandle     mParent;
+    uint16_t            mAssociationType;
+    uint32_t            mAssociationDesc;
+    uint32_t            mSequenceNumber;
+    char*               mName;
+    time_t              mDateCreated;
+    time_t              mDateModified;
+    char*               mKeywords;
+
+public:
+                        MtpObjectInfo(MtpObjectHandle handle);
+    virtual             ~MtpObjectInfo();
+
+    void                read(MtpDataPacket& packet);
+
+    void                print();
+};
+
+}; // namespace android
+
+#endif // _MTP_OBJECT_INFO_H
diff --git a/media/mtp/MtpPacket.cpp b/media/mtp/MtpPacket.cpp
index f2b3ac4..3db6abb 100644
--- a/media/mtp/MtpPacket.cpp
+++ b/media/mtp/MtpPacket.cpp
@@ -128,7 +128,6 @@
 
 #ifdef MTP_HOST
 int MtpPacket::transfer(struct usb_endpoint *ep, void* buffer, int length) {
-    printf("MtpPacket::transfer length: %d\n", length);
     if (usb_endpoint_queue(ep, buffer, length)) {
         printf("usb_endpoint_queue failed, errno: %d\n", errno);
         return -1;
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index 6a90568..88c08bf 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -360,7 +360,7 @@
     if (!mSessionOpen)
         return MTP_RESPONSE_SESSION_NOT_OPEN;
     MtpStorageID storageID = mRequest.getParameter(1);      // 0xFFFFFFFF for all storage
-    MtpObjectFormat format = mRequest.getParameter(2);      // 0x00000000 for all formats
+    MtpObjectFormat format = mRequest.getParameter(2);      // 0 for all formats
     MtpObjectHandle parent = mRequest.getParameter(3);      // 0xFFFFFFFF for objects with no parent
                                                             // 0x00000000 for all objects?
 
diff --git a/media/mtp/MtpTypes.h b/media/mtp/MtpTypes.h
index 3a9adee..3ec844f 100644
--- a/media/mtp/MtpTypes.h
+++ b/media/mtp/MtpTypes.h
@@ -37,6 +37,8 @@
 // values 0x00000000 and 0xFFFFFFFF are reserved for special purposes.
 typedef uint32_t MtpObjectHandle;
 
+// Special values
+#define MTP_PARENT_ROOT         0xFFFFFFFF       // parent is root of the storage
 #define kInvalidObjectHandle    0xFFFFFFFF
 
 // MtpObjectHandle bits and masks
diff --git a/media/mtp/mtp.h b/media/mtp/mtp.h
index 9df3a5e..7a97d7c 100644
--- a/media/mtp/mtp.h
+++ b/media/mtp/mtp.h
@@ -36,9 +36,6 @@
 #define MTP_CONTAINER_PARAMETER_OFFSET          12
 #define MTP_CONTAINER_HEADER_SIZE               12
 
-// Special values
-#define MTP_PARENT_ROOT         0xFFFFFFFF       // parent is root of the storage
-
 // MTP Types
 #define MTP_TYPE_UNDEFINED      0x0000          // Undefined
 #define MTP_TYPE_INT8           0x0001          // Signed 8-bit integer
diff --git a/media/mtp/ptptest.cpp b/media/mtp/ptptest.cpp
index 2efa4c9..5da4d45 100644
--- a/media/mtp/ptptest.cpp
+++ b/media/mtp/ptptest.cpp
@@ -23,6 +23,7 @@
 
 #include "MtpClient.h"
 #include "MtpDeviceInfo.h"
+#include "MtpObjectInfo.h"
 #include "MtpStorageInfo.h"
 
 using namespace android;
@@ -47,11 +48,24 @@
     MtpStorageIDList* storageIDs = sClient->getStorageIDs();
     if (storageIDs) {
         for (int i = 0; i < storageIDs->size(); i++) {
-            MtpStorageInfo* info = sClient->getStorageInfo((*storageIDs)[i]);
+            MtpStorageID storageID = (*storageIDs)[i];
+            MtpStorageInfo* info = sClient->getStorageInfo(storageID);
             if (info) {
                 info->print();
                 delete info;
             }
+            MtpObjectHandleList* objects = sClient->getObjectHandles(storageID, 0, MTP_PARENT_ROOT);
+            if (objects) {
+                for (int j = 0; j < objects->size(); j++) {
+                    MtpObjectHandle handle = (*objects)[j];
+                    MtpObjectInfo* info = sClient->getObjectInfo(handle);
+                    if (info) {
+                        info->print();
+                        delete info;
+                    }
+                }
+                delete objects;
+            }
         }
     }
 }