MTP: Push queries for supported formats and properties up to Java.

Change-Id: I4f117090340e3916afda3d194521a6092a672ddc
Signed-off-by: Mike Lockwood <lockwood@android.com>
diff --git a/core/java/android/provider/Mtp.java b/core/java/android/provider/Mtp.java
index 15f8666..bc764ac 100644
--- a/core/java/android/provider/Mtp.java
+++ b/core/java/android/provider/Mtp.java
@@ -308,6 +308,13 @@
         public static final int FORMAT_ABSTRACT_CONTACT = 0xBB81;
         public static final int FORMAT_VCARD_2 = 0xBB82;
 
+        // Object properties we support
+        public static final int PROPERTY_STORAGE_ID = 0xDC01;
+        public static final int PROPERTY_OBJECT_FORMAT = 0xDC02;
+        public static final int PROPERTY_OBJECT_SIZE = 0xDC04;
+        public static final int PROPERTY_OBJECT_FILE_NAME = 0xDC07;
+        public static final int PROPERTY_PARENT_OBJECT = 0xDC0B;
+
         /**
          * Object is not protected. It may be modified and deleted, and its properties
          * may be modified.
diff --git a/media/java/android/media/MtpDatabase.java b/media/java/android/media/MtpDatabase.java
index 37f9f2c..88cce46 100644
--- a/media/java/android/media/MtpDatabase.java
+++ b/media/java/android/media/MtpDatabase.java
@@ -220,6 +220,50 @@
         return -1;
     }
 
+    private int[] getSupportedPlaybackFormats() {
+        return new int[] {
+            Mtp.Object.FORMAT_ASSOCIATION,
+            Mtp.Object.FORMAT_MP3,
+            Mtp.Object.FORMAT_MPEG,
+            Mtp.Object.FORMAT_EXIF_JPEG,
+            Mtp.Object.FORMAT_TIFF_EP,
+            Mtp.Object.FORMAT_GIF,
+            Mtp.Object.FORMAT_JFIF,
+            Mtp.Object.FORMAT_PNG,
+            Mtp.Object.FORMAT_TIFF,
+            Mtp.Object.FORMAT_WMA,
+            Mtp.Object.FORMAT_OGG,
+            Mtp.Object.FORMAT_AAC,
+            Mtp.Object.FORMAT_MP4_CONTAINER,
+            Mtp.Object.FORMAT_MP2,
+            Mtp.Object.FORMAT_3GP_CONTAINER,
+            Mtp.Object.FORMAT_ABSTRACT_AV_PLAYLIST,
+            Mtp.Object.FORMAT_WPL_PLAYLIST,
+            Mtp.Object.FORMAT_M3U_PLAYLIST,
+            Mtp.Object.FORMAT_PLS_PLAYLIST,
+        };
+    }
+
+    private int[] getSupportedCaptureFormats() {
+        // no capture formats yet
+        return null;
+    }
+
+    private int[] getSupportedObjectProperties(int handle) {
+        return new int[] {
+            Mtp.Object.PROPERTY_STORAGE_ID,
+            Mtp.Object.PROPERTY_OBJECT_FORMAT,
+            Mtp.Object.PROPERTY_OBJECT_SIZE,
+            Mtp.Object.PROPERTY_OBJECT_FILE_NAME,
+            Mtp.Object.PROPERTY_PARENT_OBJECT,
+        };
+    }
+
+    private int[] getSupportedDeviceProperties() {
+        // no device properties yet
+        return null;
+    }
+
     private int getObjectProperty(int handle, int property,
                             long[] outIntValue, char[] outStringValue) {
         Log.d(TAG, "getObjectProperty: " + property);
diff --git a/media/jni/android_media_MtpDatabase.cpp b/media/jni/android_media_MtpDatabase.cpp
index bfdc872..abbea30 100644
--- a/media/jni/android_media_MtpDatabase.cpp
+++ b/media/jni/android_media_MtpDatabase.cpp
@@ -40,6 +40,10 @@
 static jmethodID method_endSendObject;
 static jmethodID method_getObjectList;
 static jmethodID method_getNumObjects;
+static jmethodID method_getSupportedPlaybackFormats;
+static jmethodID method_getSupportedCaptureFormats;
+static jmethodID method_getSupportedObjectProperties;
+static jmethodID method_getSupportedDeviceProperties;
 static jmethodID method_getObjectProperty;
 static jmethodID method_getObjectInfo;
 static jmethodID method_getObjectFilePath;
@@ -87,6 +91,13 @@
                                             MtpObjectFormat format,
                                             MtpObjectHandle parent);
 
+    // callee should delete[] the results from these
+    // results can be NULL
+    virtual MtpObjectFormatList*    getSupportedPlaybackFormats();
+    virtual MtpObjectFormatList*    getSupportedCaptureFormats();
+    virtual MtpObjectPropertyList*  getSupportedObjectProperties(MtpObjectFormat format);
+    virtual MtpDevicePropertyList*  getSupportedDeviceProperties();
+
     virtual MtpResponseCode         getObjectProperty(MtpObjectHandle handle,
                                             MtpObjectProperty property,
                                             MtpDataPacket& packet);
@@ -190,6 +201,66 @@
                 (jint)storageID, (jint)format, (jint)parent);
 }
 
+MtpObjectFormatList* MyMtpDatabase::getSupportedPlaybackFormats() {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    jintArray array = (jintArray)env->CallObjectMethod(mDatabase,
+            method_getSupportedPlaybackFormats);
+    if (!array)
+        return NULL;
+    MtpObjectFormatList* list = new MtpObjectFormatList();
+    jint* formats = env->GetIntArrayElements(array, 0);
+    jsize length = env->GetArrayLength(array);
+    for (int i = 0; i < length; i++)
+        list->push(formats[i]);
+   env->ReleaseIntArrayElements(array, formats, 0);
+   return list;
+}
+
+MtpObjectFormatList* MyMtpDatabase::getSupportedCaptureFormats() {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    jintArray array = (jintArray)env->CallObjectMethod(mDatabase,
+            method_getSupportedCaptureFormats);
+    if (!array)
+        return NULL;
+    MtpObjectFormatList* list = new MtpObjectFormatList();
+    jint* formats = env->GetIntArrayElements(array, 0);
+    jsize length = env->GetArrayLength(array);
+    for (int i = 0; i < length; i++)
+        list->push(formats[i]);
+   env->ReleaseIntArrayElements(array, formats, 0);
+   return list;
+}
+
+MtpObjectPropertyList* MyMtpDatabase::getSupportedObjectProperties(MtpObjectFormat format) {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    jintArray array = (jintArray)env->CallObjectMethod(mDatabase,
+            method_getSupportedObjectProperties, (jint)format);
+    if (!array)
+        return NULL;
+    MtpObjectPropertyList* list = new MtpObjectPropertyList();
+    jint* properties = env->GetIntArrayElements(array, 0);
+    jsize length = env->GetArrayLength(array);
+    for (int i = 0; i < length; i++)
+        list->push(properties[i]);
+   env->ReleaseIntArrayElements(array, properties, 0);
+   return list;
+}
+
+MtpDevicePropertyList* MyMtpDatabase::getSupportedDeviceProperties() {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    jintArray array = (jintArray)env->CallObjectMethod(mDatabase,
+            method_getSupportedDeviceProperties);
+    if (!array)
+        return NULL;
+    MtpDevicePropertyList* list = new MtpDevicePropertyList();
+    jint* properties = env->GetIntArrayElements(array, 0);
+    jsize length = env->GetArrayLength(array);
+    for (int i = 0; i < length; i++)
+        list->push(properties[i]);
+   env->ReleaseIntArrayElements(array, properties, 0);
+   return list;
+}
+
 MtpResponseCode MyMtpDatabase::getObjectProperty(MtpObjectHandle handle,
                                             MtpObjectProperty property,
                                             MtpDataPacket& packet) {
@@ -460,6 +531,26 @@
         LOGE("Can't find getNumObjects");
         return -1;
     }
+    method_getSupportedPlaybackFormats = env->GetMethodID(clazz, "getSupportedPlaybackFormats", "()[I");
+    if (method_getSupportedPlaybackFormats == NULL) {
+        LOGE("Can't find getSupportedPlaybackFormats");
+        return -1;
+    }
+    method_getSupportedCaptureFormats = env->GetMethodID(clazz, "getSupportedCaptureFormats", "()[I");
+    if (method_getSupportedCaptureFormats == NULL) {
+        LOGE("Can't find getSupportedCaptureFormats");
+        return -1;
+    }
+    method_getSupportedObjectProperties = env->GetMethodID(clazz, "getSupportedObjectProperties", "(I)[I");
+    if (method_getSupportedObjectProperties == NULL) {
+        LOGE("Can't find getSupportedObjectProperties");
+        return -1;
+    }
+    method_getSupportedDeviceProperties = env->GetMethodID(clazz, "getSupportedDeviceProperties", "()[I");
+    if (method_getSupportedDeviceProperties == NULL) {
+        LOGE("Can't find getSupportedDeviceProperties");
+        return -1;
+    }
     method_getObjectProperty = env->GetMethodID(clazz, "getObjectProperty", "(II[J[C)I");
     if (method_getObjectProperty == NULL) {
         LOGE("Can't find getObjectProperty");
diff --git a/media/mtp/MtpDataPacket.cpp b/media/mtp/MtpDataPacket.cpp
index c159e20..9bfd00f 100644
--- a/media/mtp/MtpDataPacket.cpp
+++ b/media/mtp/MtpDataPacket.cpp
@@ -266,6 +266,13 @@
         putUInt16(*values++);
 }
 
+void MtpDataPacket::putAUInt16(const UInt16List* values) {
+    size_t count = (values ? values->size() : 0);
+    putUInt32(count);
+    for (size_t i = 0; i < count; i++)
+        putUInt16((*values)[i]);
+}
+
 void MtpDataPacket::putAInt32(const int32_t* values, int count) {
     putUInt32(count);
     for (int i = 0; i < count; i++)
diff --git a/media/mtp/MtpDataPacket.h b/media/mtp/MtpDataPacket.h
index e8314d7..b458286 100644
--- a/media/mtp/MtpDataPacket.h
+++ b/media/mtp/MtpDataPacket.h
@@ -74,6 +74,7 @@
     void                putAUInt8(const uint8_t* values, int count);
     void                putAInt16(const int16_t* values, int count);
     void                putAUInt16(const uint16_t* values, int count);
+    void                putAUInt16(const UInt16List* values);
     void                putAInt32(const int32_t* values, int count);
     void                putAUInt32(const uint32_t* values, int count);
     void                putAUInt32(const UInt32List* list);
diff --git a/media/mtp/MtpDatabase.h b/media/mtp/MtpDatabase.h
index 02bb0d9..17823df 100644
--- a/media/mtp/MtpDatabase.h
+++ b/media/mtp/MtpDatabase.h
@@ -51,6 +51,13 @@
                                             MtpObjectFormat format,
                                             MtpObjectHandle parent) = 0;
 
+    // callee should delete[] the results from these
+    // results can be NULL
+    virtual MtpObjectFormatList*    getSupportedPlaybackFormats() = 0;
+    virtual MtpObjectFormatList*    getSupportedCaptureFormats() = 0;
+    virtual MtpObjectPropertyList*  getSupportedObjectProperties(MtpObjectFormat format) = 0;
+    virtual MtpDevicePropertyList*  getSupportedDeviceProperties() = 0;
+
     virtual MtpResponseCode         getObjectProperty(MtpObjectHandle handle,
                                             MtpObjectProperty property,
                                             MtpDataPacket& packet) = 0;
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index 082d924..6d2eec3 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -78,46 +78,6 @@
     MTP_EVENT_OBJECT_REMOVED,
 };
 
-static const MtpObjectProperty kSupportedObjectProperties[] = {
-    MTP_PROPERTY_STORAGE_ID,
-    MTP_PROPERTY_OBJECT_FORMAT,
-    MTP_PROPERTY_OBJECT_SIZE,
-    MTP_PROPERTY_OBJECT_FILE_NAME,
-    MTP_PROPERTY_PARENT_OBJECT,
-};
-
-static const MtpObjectFormat kSupportedPlaybackFormats[] = {
-    // MTP_FORMAT_UNDEFINED,
-    MTP_FORMAT_ASSOCIATION,
-    // MTP_FORMAT_TEXT,
-    // MTP_FORMAT_HTML,
-    MTP_FORMAT_MP3,
-    //MTP_FORMAT_AVI,
-    MTP_FORMAT_MPEG,
-    // MTP_FORMAT_ASF,
-    MTP_FORMAT_EXIF_JPEG,
-    MTP_FORMAT_TIFF_EP,
-    // MTP_FORMAT_BMP,
-    MTP_FORMAT_GIF,
-    MTP_FORMAT_JFIF,
-    MTP_FORMAT_PNG,
-    MTP_FORMAT_TIFF,
-    MTP_FORMAT_WMA,
-    MTP_FORMAT_OGG,
-    MTP_FORMAT_AAC,
-    // MTP_FORMAT_FLAC,
-    // MTP_FORMAT_WMV,
-    MTP_FORMAT_MP4_CONTAINER,
-    MTP_FORMAT_MP2,
-    MTP_FORMAT_3GP_CONTAINER,
-    // MTP_FORMAT_ABSTRACT_AUDIO_ALBUM,
-    MTP_FORMAT_ABSTRACT_AV_PLAYLIST,
-    MTP_FORMAT_WPL_PLAYLIST,
-    MTP_FORMAT_M3U_PLAYLIST,
-    // MTP_FORMAT_MPL_PLAYLIST,
-    MTP_FORMAT_PLS_PLAYLIST,
-};
-
 MtpServer::MtpServer(int fd, MtpDatabase* database,
                     int fileGroup, int filePerm, int directoryPerm)
     :   mFD(fd),
@@ -354,6 +314,10 @@
     MtpStringBuffer   string;
     char prop_value[PROPERTY_VALUE_MAX];
 
+    MtpObjectFormatList* playbackFormats = mDatabase->getSupportedPlaybackFormats();
+    MtpObjectFormatList* captureFormats = mDatabase->getSupportedCaptureFormats();
+    MtpDevicePropertyList* deviceProperties = mDatabase->getSupportedDeviceProperties();
+
     // fill in device info
     mData.putUInt16(MTP_STANDARD_VERSION);
     mData.putUInt32(6); // MTP Vendor Extension ID
@@ -365,10 +329,9 @@
             sizeof(kSupportedOperationCodes) / sizeof(uint16_t)); // Operations Supported
     mData.putAUInt16(kSupportedEventCodes,
             sizeof(kSupportedEventCodes) / sizeof(uint16_t)); // Events Supported
-    mData.putEmptyArray(); // Device Properties Supported
-    mData.putEmptyArray(); // Capture Formats
-    mData.putAUInt16(kSupportedPlaybackFormats,
-            sizeof(kSupportedPlaybackFormats) / sizeof(uint16_t)); // Playback Formats
+    mData.putAUInt16(deviceProperties); // Device Properties Supported
+    mData.putAUInt16(captureFormats); // Capture Formats
+    mData.putAUInt16(playbackFormats);  // Playback Formats
     // FIXME
     string.set("Google, Inc.");
     mData.putString(string);   // Manufacturer
@@ -383,6 +346,10 @@
     string.set(prop_value);
     mData.putString(string);   // Serial Number
 
+    delete playbackFormats;
+    delete captureFormats;
+    delete deviceProperties;
+
     return MTP_RESPONSE_OK;
 }
 
@@ -443,8 +410,9 @@
     if (!mSessionOpen)
         return MTP_RESPONSE_SESSION_NOT_OPEN;
     MtpObjectFormat format = mRequest.getParameter(1);
-    mData.putAUInt16(kSupportedObjectProperties,
-            sizeof(kSupportedObjectProperties) / sizeof(uint16_t));
+    MtpDevicePropertyList* properties = mDatabase->getSupportedObjectProperties(format);
+    mData.putAUInt16(properties);
+    delete[] properties;
     return MTP_RESPONSE_OK;
 }
 
diff --git a/media/mtp/MtpTypes.h b/media/mtp/MtpTypes.h
index 2a895a7..7e3c009 100644
--- a/media/mtp/MtpTypes.h
+++ b/media/mtp/MtpTypes.h
@@ -78,6 +78,7 @@
 typedef Vector<int32_t> Int32List;
 typedef Vector<int64_t> Int64List;
 
+typedef UInt16List MtpObjectPropertyList;
 typedef UInt16List MtpDevicePropertyList;
 typedef UInt16List MtpObjectFormatList;
 typedef UInt32List MtpObjectHandleList;