diff options
author | Mike Lockwood <lockwood@android.com> | 2010-09-02 14:57:30 -0400 |
---|---|---|
committer | Mike Lockwood <lockwood@android.com> | 2010-09-02 14:59:26 -0400 |
commit | 59e3f0db0855567a95f783f6d1ec36a7cfc4ea83 (patch) | |
tree | fdbc67ccc1fb82526fd0b6f6decb156f905c4d95 | |
parent | 1770b872897d208a6f1fd4c7c9c4203cd3b6af4d (diff) | |
download | frameworks_base-59e3f0db0855567a95f783f6d1ec36a7cfc4ea83.zip frameworks_base-59e3f0db0855567a95f783f6d1ec36a7cfc4ea83.tar.gz frameworks_base-59e3f0db0855567a95f783f6d1ec36a7cfc4ea83.tar.bz2 |
MTP: Implement support for getting/setting device properties
Added support for the "device friendly name" and "synchonization partner"
properties, which are required by Microsoft.
Change-Id: Ic0443333d75f7d98a2d902a790b9d505a56d4eef
Signed-off-by: Mike Lockwood <lockwood@android.com>
-rw-r--r-- | media/java/android/media/MtpDatabase.java | 93 | ||||
-rw-r--r-- | media/jni/android_media_MtpDatabase.cpp | 241 | ||||
-rw-r--r-- | media/mtp/MtpDevice.cpp | 2 | ||||
-rw-r--r-- | media/mtp/MtpProperty.cpp | 5 | ||||
-rw-r--r-- | media/mtp/MtpProperty.h | 10 | ||||
-rw-r--r-- | media/mtp/MtpServer.cpp | 5 |
6 files changed, 332 insertions, 24 deletions
diff --git a/media/java/android/media/MtpDatabase.java b/media/java/android/media/MtpDatabase.java index 0c8326e..9016e68 100644 --- a/media/java/android/media/MtpDatabase.java +++ b/media/java/android/media/MtpDatabase.java @@ -21,6 +21,7 @@ import android.content.ContentValues; import android.content.IContentProvider; import android.content.Intent; import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; import android.net.Uri; import android.os.RemoteException; import android.provider.MediaStore.Audio; @@ -44,6 +45,10 @@ public class MtpDatabase { // true if the database has been modified in the current MTP session private boolean mDatabaseModified; + // database for writable MTP device properties + private SQLiteDatabase mDevicePropDb; + private static final int DEVICE_PROPERTIES_DATABASE_VERSION = 1; + // FIXME - this should be passed in via the constructor private final int mStorageID = 0x00010001; @@ -69,6 +74,9 @@ public class MtpDatabase { private static final String PARENT_FORMAT_WHERE = PARENT_WHERE + " AND " + MtpObjects.ObjectColumns.FORMAT + "=?"; + private static final String[] DEVICE_PROPERTY_PROJECTION = new String[] { "_id", "value" }; + private static final String DEVICE_PROPERTY_WHERE = "code=?"; + private final MediaScanner mMediaScanner; static { @@ -83,6 +91,7 @@ public class MtpDatabase { mVolumeName = volumeName; mObjectsUri = MtpObjects.getContentUri(volumeName); mMediaScanner = new MediaScanner(context); + openDevicePropertiesDatabase(context); } @Override @@ -94,6 +103,22 @@ public class MtpDatabase { } } + private void openDevicePropertiesDatabase(Context context) { + mDevicePropDb = context.openOrCreateDatabase("device-properties", Context.MODE_PRIVATE, null); + int version = mDevicePropDb.getVersion(); + + // initialize if necessary + if (version != DEVICE_PROPERTIES_DATABASE_VERSION) { + mDevicePropDb.execSQL("CREATE TABLE properties (" + + "_id INTEGER PRIMARY KEY AUTOINCREMENT," + + "code INTEGER UNIQUE ON CONFLICT REPLACE," + + "value TEXT" + + ");"); + mDevicePropDb.execSQL("CREATE INDEX property_index ON properties (code);"); + mDevicePropDb.setVersion(DEVICE_PROPERTIES_DATABASE_VERSION); + } + } + private int beginSendObject(String path, int format, int parent, int storage, long size, long modified) { mDatabaseModified = true; @@ -257,8 +282,10 @@ public class MtpDatabase { } private int[] getSupportedDeviceProperties() { - // no device properties yet - return null; + return new int[] { + MtpConstants.DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER, + MtpConstants.DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME, + }; } private int getObjectProperty(int handle, int property, @@ -342,6 +369,68 @@ public class MtpDatabase { return MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE; } + private int setObjectProperty(int handle, int property, + long intValue, String stringValue) { + Log.d(TAG, "setObjectProperty: " + property); + return MtpConstants.RESPONSE_OBJECT_PROP_NOT_SUPPORTED; + } + + private int getDeviceProperty(int property, long[] outIntValue, char[] outStringValue) { + Log.d(TAG, "getDeviceProperty: " + property); + + switch (property) { + case MtpConstants.DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER: + case MtpConstants.DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME: + // writable string properties kept in our device property database + Cursor c = null; + try { + c = mDevicePropDb.query("properties", DEVICE_PROPERTY_PROJECTION, + DEVICE_PROPERTY_WHERE, new String[] { Integer.toString(property) }, + null, null, null); + + if (c != null && c.moveToNext()) { + String value = c.getString(1); + int length = value.length(); + if (length > 255) { + length = 255; + } + value.getChars(0, length, outStringValue, 0); + outStringValue[length] = 0; + } else { + outStringValue[0] = 0; + } + return MtpConstants.RESPONSE_OK; + } finally { + if (c != null) { + c.close(); + } + } + } + + return MtpConstants.RESPONSE_DEVICE_PROP_NOT_SUPPORTED; + } + + private int setDeviceProperty(int property, long intValue, String stringValue) { + Log.d(TAG, "setDeviceProperty: " + property + " : " + stringValue); + + switch (property) { + case MtpConstants.DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER: + case MtpConstants.DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME: + // writable string properties kept in our device property database + try { + ContentValues values = new ContentValues(); + values.put("code", property); + values.put("value", stringValue); + mDevicePropDb.insert("properties", "code", values); + return MtpConstants.RESPONSE_OK; + } catch (Exception e) { + return MtpConstants.RESPONSE_GENERAL_ERROR; + } + } + + return MtpConstants.RESPONSE_DEVICE_PROP_NOT_SUPPORTED; + } + private boolean getObjectInfo(int handle, int[] outStorageFormatParent, char[] outName, long[] outSizeModified) { Log.d(TAG, "getObjectInfo: " + handle); diff --git a/media/jni/android_media_MtpDatabase.cpp b/media/jni/android_media_MtpDatabase.cpp index 4046287..1842cb2 100644 --- a/media/jni/android_media_MtpDatabase.cpp +++ b/media/jni/android_media_MtpDatabase.cpp @@ -30,6 +30,7 @@ #include "MtpDatabase.h" #include "MtpDataPacket.h" #include "MtpProperty.h" +#include "MtpStringBuffer.h" #include "MtpUtils.h" #include "mtp.h" @@ -47,6 +48,8 @@ static jmethodID method_getSupportedObjectProperties; static jmethodID method_getSupportedDeviceProperties; static jmethodID method_getObjectProperty; static jmethodID method_setObjectProperty; +static jmethodID method_getDeviceProperty; +static jmethodID method_setDeviceProperty; static jmethodID method_getObjectInfo; static jmethodID method_getObjectFilePath; static jmethodID method_deleteFile; @@ -127,7 +130,8 @@ public: int64_t& fileLength); virtual MtpResponseCode deleteFile(MtpObjectHandle handle); - bool getPropertyInfo(MtpObjectProperty property, int& type); + bool getObjectPropertyInfo(MtpObjectProperty property, int& type); + bool getDevicePropertyInfo(MtpDeviceProperty property, int& type); virtual MtpObjectHandleList* getObjectReferences(MtpObjectHandle handle); @@ -323,14 +327,16 @@ MtpResponseCode MyMtpDatabase::getObjectPropertyValue(MtpObjectHandle handle, MtpDataPacket& packet) { int type; - if (!getPropertyInfo(property, type)) - return MTP_RESPONSE_INVALID_OBJECT_PROP_CODE; + if (!getObjectPropertyInfo(property, type)) + return MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED; JNIEnv* env = AndroidRuntime::getJNIEnv(); jint result = env->CallIntMethod(mDatabase, method_getObjectProperty, (jint)handle, (jint)property, mLongBuffer, mStringBuffer); - if (result != MTP_RESPONSE_OK) + if (result != MTP_RESPONSE_OK) { + checkAndClearExceptionFromCallback(env, __FUNCTION__); return result; + } jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0); jlong longValue = longValues[0]; @@ -384,8 +390,8 @@ MtpResponseCode MyMtpDatabase::getObjectPropertyValue(MtpObjectHandle handle, break; } default: - LOGE("unsupported object type\n"); - return MTP_RESPONSE_INVALID_OBJECT_HANDLE; + LOGE("unsupported type in getObjectPropertyValue\n"); + return MTP_RESPONSE_INVALID_OBJECT_PROP_FORMAT; } checkAndClearExceptionFromCallback(env, __FUNCTION__); @@ -395,17 +401,179 @@ MtpResponseCode MyMtpDatabase::getObjectPropertyValue(MtpObjectHandle handle, MtpResponseCode MyMtpDatabase::setObjectPropertyValue(MtpObjectHandle handle, MtpObjectProperty property, MtpDataPacket& packet) { - return -1; + int type; + + if (!getObjectPropertyInfo(property, type)) + return MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED; + + JNIEnv* env = AndroidRuntime::getJNIEnv(); + jlong longValue = 0; + jstring stringValue = NULL; + + switch (type) { + case MTP_TYPE_INT8: + longValue = packet.getInt8(); + break; + case MTP_TYPE_UINT8: + longValue = packet.getUInt8(); + break; + case MTP_TYPE_INT16: + longValue = packet.getInt16(); + break; + case MTP_TYPE_UINT16: + longValue = packet.getUInt16(); + break; + case MTP_TYPE_INT32: + longValue = packet.getInt32(); + break; + case MTP_TYPE_UINT32: + longValue = packet.getUInt32(); + break; + case MTP_TYPE_INT64: + longValue = packet.getInt64(); + break; + case MTP_TYPE_UINT64: + longValue = packet.getUInt64(); + break; + case MTP_TYPE_STR: + { + MtpStringBuffer buffer; + packet.getString(buffer); + stringValue = env->NewStringUTF((const char *)buffer); + break; + } + default: + LOGE("unsupported type in getObjectPropertyValue\n"); + return MTP_RESPONSE_INVALID_OBJECT_PROP_FORMAT; + } + + jint result = env->CallIntMethod(mDatabase, method_setObjectProperty, + (jint)handle, (jint)property, longValue, stringValue); + + checkAndClearExceptionFromCallback(env, __FUNCTION__); + return result; } MtpResponseCode MyMtpDatabase::getDevicePropertyValue(MtpDeviceProperty property, MtpDataPacket& packet) { - return -1; + + int type; + + if (!getDevicePropertyInfo(property, type)) + return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED; + + JNIEnv* env = AndroidRuntime::getJNIEnv(); + jint result = env->CallIntMethod(mDatabase, method_getDeviceProperty, + (jint)property, mLongBuffer, mStringBuffer); + if (result != MTP_RESPONSE_OK) { + checkAndClearExceptionFromCallback(env, __FUNCTION__); + return result; + } + + jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0); + jlong longValue = longValues[0]; + env->ReleaseLongArrayElements(mLongBuffer, longValues, 0); + + switch (type) { + case MTP_TYPE_INT8: + packet.putInt8(longValue); + break; + case MTP_TYPE_UINT8: + packet.putUInt8(longValue); + break; + case MTP_TYPE_INT16: + packet.putInt16(longValue); + break; + case MTP_TYPE_UINT16: + packet.putUInt16(longValue); + break; + case MTP_TYPE_INT32: + packet.putInt32(longValue); + break; + case MTP_TYPE_UINT32: + packet.putUInt32(longValue); + break; + case MTP_TYPE_INT64: + packet.putInt64(longValue); + break; + case MTP_TYPE_UINT64: + packet.putUInt64(longValue); + break; + case MTP_TYPE_INT128: + packet.putInt128(longValue); + break; + case MTP_TYPE_UINT128: + packet.putInt128(longValue); + break; + case MTP_TYPE_STR: + { + jchar* str = env->GetCharArrayElements(mStringBuffer, 0); + packet.putString(str); + env->ReleaseCharArrayElements(mStringBuffer, str, 0); + break; + } + default: + LOGE("unsupported type in getDevicePropertyValue\n"); + return MTP_RESPONSE_INVALID_DEVICE_PROP_FORMAT; + } + + checkAndClearExceptionFromCallback(env, __FUNCTION__); + return MTP_RESPONSE_OK; } MtpResponseCode MyMtpDatabase::setDevicePropertyValue(MtpDeviceProperty property, MtpDataPacket& packet) { - return -1; + int type; + + if (!getDevicePropertyInfo(property, type)) + return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED; + + JNIEnv* env = AndroidRuntime::getJNIEnv(); + jlong longValue = 0; + jstring stringValue = NULL; + + switch (type) { + case MTP_TYPE_INT8: + longValue = packet.getInt8(); + break; + case MTP_TYPE_UINT8: + longValue = packet.getUInt8(); + break; + case MTP_TYPE_INT16: + longValue = packet.getInt16(); + break; + case MTP_TYPE_UINT16: + longValue = packet.getUInt16(); + break; + case MTP_TYPE_INT32: + longValue = packet.getInt32(); + break; + case MTP_TYPE_UINT32: + longValue = packet.getUInt32(); + break; + case MTP_TYPE_INT64: + longValue = packet.getInt64(); + break; + case MTP_TYPE_UINT64: + longValue = packet.getUInt64(); + break; + case MTP_TYPE_STR: + { + MtpStringBuffer buffer; + packet.getString(buffer); + stringValue = env->NewStringUTF((const char *)buffer); + break; + } + default: + LOGE("unsupported type in setDevicePropertyValue\n"); + return MTP_RESPONSE_INVALID_OBJECT_PROP_FORMAT; + } + + jint result = env->CallIntMethod(mDatabase, method_setDeviceProperty, + (jint)property, longValue, stringValue); + + checkAndClearExceptionFromCallback(env, __FUNCTION__); + return result; } MtpResponseCode MyMtpDatabase::resetDeviceProperty(MtpDeviceProperty property) { @@ -473,8 +641,10 @@ MtpResponseCode MyMtpDatabase::getObjectFilePath(MtpObjectHandle handle, JNIEnv* env = AndroidRuntime::getJNIEnv(); jint result = env->CallIntMethod(mDatabase, method_getObjectFilePath, (jint)handle, mStringBuffer, mLongBuffer); - if (result != MTP_RESPONSE_OK) + if (result != MTP_RESPONSE_OK) { + checkAndClearExceptionFromCallback(env, __FUNCTION__); return result; + } jchar* str = env->GetCharArrayElements(mStringBuffer, 0); filePath.setTo(str, strlen16(str)); @@ -501,7 +671,7 @@ struct PropertyTableEntry { int type; }; -static const PropertyTableEntry kPropertyTable[] = { +static const PropertyTableEntry kObjectPropertyTable[] = { { MTP_PROPERTY_PARENT_OBJECT, MTP_TYPE_UINT32 }, { MTP_PROPERTY_STORAGE_ID, MTP_TYPE_UINT32 }, { MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16 }, @@ -510,9 +680,26 @@ static const PropertyTableEntry kPropertyTable[] = { { MTP_PROPERTY_DATE_MODIFIED, MTP_TYPE_STR }, }; -bool MyMtpDatabase::getPropertyInfo(MtpObjectProperty property, int& type) { - int count = sizeof(kPropertyTable) / sizeof(kPropertyTable[0]); - const PropertyTableEntry* entry = kPropertyTable; +static const PropertyTableEntry kDevicePropertyTable[] = { + { MTP_DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER, MTP_TYPE_STR }, + { MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME, MTP_TYPE_STR }, +}; + +bool MyMtpDatabase::getObjectPropertyInfo(MtpObjectProperty property, int& type) { + int count = sizeof(kObjectPropertyTable) / sizeof(kObjectPropertyTable[0]); + const PropertyTableEntry* entry = kObjectPropertyTable; + for (int i = 0; i < count; i++, entry++) { + if (entry->property == property) { + type = entry->type; + return true; + } + } + return false; +} + +bool MyMtpDatabase::getDevicePropertyInfo(MtpDeviceProperty property, int& type) { + int count = sizeof(kDevicePropertyTable) / sizeof(kDevicePropertyTable[0]); + const PropertyTableEntry* entry = kDevicePropertyTable; for (int i = 0; i < count; i++, entry++) { if (entry->property == property) { type = entry->type; @@ -587,7 +774,16 @@ MtpProperty* MyMtpDatabase::getObjectPropertyDesc(MtpObjectProperty property, } MtpProperty* MyMtpDatabase::getDevicePropertyDesc(MtpDeviceProperty property) { - return NULL; + MtpProperty* result = NULL; + switch (property) { + case MTP_DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER: + case MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME: + // writeable string properties + result = new MtpProperty(property, MTP_TYPE_STR, true); + break; + } + + return result; } void MyMtpDatabase::sessionStarted() { @@ -695,6 +891,21 @@ int register_android_media_MtpDatabase(JNIEnv *env) LOGE("Can't find getObjectProperty"); return -1; } + method_setObjectProperty = env->GetMethodID(clazz, "setObjectProperty", "(IIJLjava/lang/String;)I"); + if (method_setObjectProperty == NULL) { + LOGE("Can't find setObjectProperty"); + return -1; + } + method_getDeviceProperty = env->GetMethodID(clazz, "getDeviceProperty", "(I[J[C)I"); + if (method_getDeviceProperty == NULL) { + LOGE("Can't find getDeviceProperty"); + return -1; + } + method_setDeviceProperty = env->GetMethodID(clazz, "setDeviceProperty", "(IJLjava/lang/String;)I"); + if (method_setDeviceProperty == NULL) { + LOGE("Can't find setDeviceProperty"); + return -1; + } method_getObjectInfo = env->GetMethodID(clazz, "getObjectInfo", "(I[I[C[J)Z"); if (method_getObjectInfo == NULL) { LOGE("Can't find getObjectInfo"); diff --git a/media/mtp/MtpDevice.cpp b/media/mtp/MtpDevice.cpp index bd68f75..fca0142 100644 --- a/media/mtp/MtpDevice.cpp +++ b/media/mtp/MtpDevice.cpp @@ -342,7 +342,7 @@ MtpProperty* MtpDevice::getDevicePropDesc(MtpDeviceProperty code) { MtpResponseCode ret = readResponse(); if (ret == MTP_RESPONSE_OK) { MtpProperty* property = new MtpProperty; - property->read(mData, true); + property->read(mData); return property; } return NULL; diff --git a/media/mtp/MtpProperty.cpp b/media/mtp/MtpProperty.cpp index 932ad6a..c7a91d6 100644 --- a/media/mtp/MtpProperty.cpp +++ b/media/mtp/MtpProperty.cpp @@ -120,7 +120,7 @@ MtpProperty::~MtpProperty() { delete[] mEnumValues; } -void MtpProperty::read(MtpDataPacket& packet, bool deviceProp) { +void MtpProperty::read(MtpDataPacket& packet) { mCode = packet.getUInt16(); mType = packet.getUInt16(); @@ -141,7 +141,7 @@ void MtpProperty::read(MtpDataPacket& packet, bool deviceProp) { break; default: readValue(packet, mDefaultValue); - if (deviceProp) + if (isDeviceProperty()) readValue(packet, mCurrentValue); } mGroupCode = packet.getUInt32(); @@ -159,7 +159,6 @@ void MtpProperty::read(MtpDataPacket& packet, bool deviceProp) { } } -// FIXME - only works for object properties void MtpProperty::write(MtpDataPacket& packet) { packet.putUInt16(mCode); packet.putUInt16(mType); diff --git a/media/mtp/MtpProperty.h b/media/mtp/MtpProperty.h index c5b4e28..64cfb93 100644 --- a/media/mtp/MtpProperty.h +++ b/media/mtp/MtpProperty.h @@ -65,16 +65,22 @@ public: inline MtpPropertyCode getPropertyCode() const { return mCode; } - void read(MtpDataPacket& packet, bool deviceProp); + void read(MtpDataPacket& packet); void write(MtpDataPacket& packet); void print(); + inline bool isDeviceProperty() const { + return ( ((mCode & 0xF000) == 0x5000) + || ((mCode & 0xF800) == 0xD000)); + } + private: void readValue(MtpDataPacket& packet, MtpPropertyValue& value); void writeValue(MtpDataPacket& packet, MtpPropertyValue& value); MtpPropertyValue* readArrayValues(MtpDataPacket& packet, int& length); - void writeArrayValues(MtpDataPacket& packet, MtpPropertyValue* values, int length); + void writeArrayValues(MtpDataPacket& packet, + MtpPropertyValue* values, int length); }; }; // namespace android diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp index c982114..3d3bd62 100644 --- a/media/mtp/MtpServer.cpp +++ b/media/mtp/MtpServer.cpp @@ -55,7 +55,7 @@ static const MtpOperationCode kSupportedOperationCodes[] = { // MTP_OPERATION_SELF_TEST, // MTP_OPERATION_SET_OBJECT_PROTECTION, // MTP_OPERATION_POWER_DOWN, -// MTP_OPERATION_GET_DEVICE_PROP_DESC, + MTP_OPERATION_GET_DEVICE_PROP_DESC, MTP_OPERATION_GET_DEVICE_PROP_VALUE, MTP_OPERATION_SET_DEVICE_PROP_VALUE, MTP_OPERATION_RESET_DEVICE_PROP_VALUE, @@ -288,6 +288,9 @@ bool MtpServer::handleRequest() { case MTP_OPERATION_GET_OBJECT_PROP_DESC: response = doGetObjectPropDesc(); break; + case MTP_OPERATION_GET_DEVICE_PROP_DESC: + response = doGetDevicePropDesc(); + break; default: response = MTP_RESPONSE_OPERATION_NOT_SUPPORTED; break; |