Wire uploading to MtpDocumentsProvider.
This patch does not yet allow to upload files, but uploading (creating)
directories already works.
Bug: 22545670
Change-Id: If4d5a53aa26f791475bb1a783e0ac9540d6760c1
diff --git a/api/current.txt b/api/current.txt
index 3e1f5a5..9f02047 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -18136,7 +18136,7 @@
method public final int getThumbPixWidth();
}
- public class MtpObjectInfo.Builder {
+ public static class MtpObjectInfo.Builder {
ctor public MtpObjectInfo.Builder();
ctor public MtpObjectInfo.Builder(android.mtp.MtpObjectInfo);
method public android.mtp.MtpObjectInfo build();
diff --git a/api/system-current.txt b/api/system-current.txt
index 984d395..7c4c81e 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -19649,7 +19649,7 @@
method public final int getThumbPixWidth();
}
- public class MtpObjectInfo.Builder {
+ public static class MtpObjectInfo.Builder {
ctor public MtpObjectInfo.Builder();
ctor public MtpObjectInfo.Builder(android.mtp.MtpObjectInfo);
method public android.mtp.MtpObjectInfo build();
diff --git a/media/java/android/mtp/MtpObjectInfo.java b/media/java/android/mtp/MtpObjectInfo.java
index d2824b5..f79d52e 100644
--- a/media/java/android/mtp/MtpObjectInfo.java
+++ b/media/java/android/mtp/MtpObjectInfo.java
@@ -256,7 +256,7 @@
/**
* Builds a new object info instance.
*/
- public class Builder {
+ public static class Builder {
private MtpObjectInfo mObjectInfo;
public Builder() {
diff --git a/media/jni/android_mtp_MtpDevice.cpp b/media/jni/android_mtp_MtpDevice.cpp
index ad804f3..9dd3861 100644
--- a/media/jni/android_mtp_MtpDevice.cpp
+++ b/media/jni/android_mtp_MtpDevice.cpp
@@ -430,12 +430,14 @@
android_mtp_MtpDevice_send_object_info(JNIEnv *env, jobject thiz, jobject info)
{
MtpDevice* device = get_device_from_object(env, thiz);
- if (!device)
+ if (!device) {
return JNI_FALSE;
+ }
// Updating existing objects is not supported.
- if (env->GetIntField(info, field_objectInfo_handle) != -1)
+ if (env->GetIntField(info, field_objectInfo_handle) != -1) {
return JNI_FALSE;
+ }
MtpObjectInfo* object_info = new MtpObjectInfo(-1);
object_info->mStorageID = env->GetIntField(info, field_objectInfo_storageId);
@@ -456,17 +458,21 @@
object_info->mSequenceNumber = env->GetIntField(info, field_objectInfo_sequenceNumber);
jstring name_jstring = (jstring) env->GetObjectField(info, field_objectInfo_name);
- const char* name_string = env->GetStringUTFChars(name_jstring, NULL);
- object_info->mName = strdup(name_string);
- env->ReleaseStringUTFChars(name_jstring, name_string);
+ if (name_jstring != NULL) {
+ const char* name_string = env->GetStringUTFChars(name_jstring, NULL);
+ object_info->mName = strdup(name_string);
+ env->ReleaseStringUTFChars(name_jstring, name_string);
+ }
object_info->mDateCreated = env->GetLongField(info, field_objectInfo_dateCreated) / 1000LL;
object_info->mDateModified = env->GetLongField(info, field_objectInfo_dateModified) / 1000LL;
jstring keywords_jstring = (jstring) env->GetObjectField(info, field_objectInfo_keywords);
- const char* keywords_string = env->GetStringUTFChars(keywords_jstring, NULL);
- object_info->mKeywords = strdup(keywords_string);
- env->ReleaseStringUTFChars(keywords_jstring, keywords_string);
+ if (keywords_jstring != NULL) {
+ const char* keywords_string = env->GetStringUTFChars(keywords_jstring, NULL);
+ object_info->mKeywords = strdup(keywords_string);
+ env->ReleaseStringUTFChars(keywords_jstring, keywords_string);
+ }
int object_handle = device->sendObjectInfo(object_info);
if (object_handle == -1) {
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocument.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocument.java
index 98775b3..7126694 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocument.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocument.java
@@ -32,6 +32,7 @@
private final Date mDateModified;
private final int mSize;
private final int mThumbSize;
+ private final boolean mReadOnly;
/**
* Constructor for root document.
@@ -40,9 +41,10 @@
this(DUMMY_HANDLE_FOR_ROOT,
0x3001, // Directory.
root.mDescription,
- null, // Unknown,
+ null, // Unknown name.
(int) Math.min(root.mMaxCapacity - root.mFreeSpace, Integer.MAX_VALUE),
- 0);
+ 0, // Total size.
+ true); // Writable.
}
MtpDocument(MtpObjectInfo objectInfo) {
@@ -51,7 +53,8 @@
objectInfo.getName(),
objectInfo.getDateModified() != 0 ? new Date(objectInfo.getDateModified()) : null,
objectInfo.getCompressedSize(),
- objectInfo.getThumbCompressedSize());
+ objectInfo.getThumbCompressedSize(),
+ objectInfo.getProtectionStatus() != 0);
}
MtpDocument(int objectHandle,
@@ -59,13 +62,15 @@
String name,
Date dateModified,
int size,
- int thumbSize) {
+ int thumbSize,
+ boolean readOnly) {
this.mObjectHandle = objectHandle;
this.mFormat = format;
this.mName = name;
this.mDateModified = dateModified;
this.mSize = size;
this.mThumbSize = thumbSize;
+ this.mReadOnly = readOnly;
}
void addToCursor(Identifier rootIdentifier, MatrixCursor.RowBuilder builder) {
@@ -82,7 +87,7 @@
builder.add(Document.COLUMN_DOCUMENT_ID, identifier.toDocumentId());
builder.add(Document.COLUMN_DISPLAY_NAME, mName);
- builder.add(Document.COLUMN_MIME_TYPE, getMimeType());
+ builder.add(Document.COLUMN_MIME_TYPE, formatTypeToMimeType(mFormat));
builder.add(
Document.COLUMN_LAST_MODIFIED,
mDateModified != null ? mDateModified.getTime() : null);
@@ -90,9 +95,9 @@
builder.add(Document.COLUMN_SIZE, mSize);
}
- private String getMimeType() {
+ static String formatTypeToMimeType(int format) {
// TODO: Add complete list of mime types.
- switch (mFormat) {
+ switch (format) {
case 0x3001:
return DocumentsContract.Document.MIME_TYPE_DIR;
case 0x3009:
@@ -100,7 +105,21 @@
case 0x3801:
return "image/jpeg";
default:
- return "";
+ return "application/octet-stream";
+ }
+ }
+
+ static int mimeTypeToFormatType(String mimeType) {
+ // TODO: Add complete list of mime types.
+ switch (mimeType.toLowerCase()) {
+ case Document.MIME_TYPE_DIR:
+ return 0x3001;
+ case "audio/mp3":
+ return 0x3009;
+ case "image/jpeg":
+ return 0x3801;
+ default:
+ return 0x3000; // Undefined object.
}
}
}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
index 3a98a58..7536415 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
@@ -96,7 +96,7 @@
final Identifier rootIdentifier = new Identifier(root.mDeviceId, root.mStorageId);
final MatrixCursor.RowBuilder builder = cursor.newRow();
builder.add(Root.COLUMN_ROOT_ID, rootIdentifier.toRootId());
- builder.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_IS_CHILD);
+ builder.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE);
builder.add(Root.COLUMN_TITLE, root.mDescription);
builder.add(
Root.COLUMN_DOCUMENT_ID,
@@ -214,6 +214,24 @@
mDocumentLoader.clearCache();
}
+ @Override
+ public String createDocument(String parentDocumentId, String mimeType, String displayName)
+ throws FileNotFoundException {
+ try {
+ final Identifier parentId = Identifier.createFromDocumentId(parentDocumentId);
+ final int objectHandle = mMtpManager.createDocument(
+ parentId.mDeviceId, parentId.mStorageId, parentId.mObjectHandle, mimeType,
+ displayName);
+ final String documentId = new Identifier(parentId.mDeviceId, parentId.mStorageId,
+ objectHandle).toDocumentId();
+ notifyChildDocumentsChange(parentDocumentId);
+ return documentId;
+ } catch (IOException error) {
+ Log.e(TAG, error.getMessage());
+ throw new FileNotFoundException(error.getMessage());
+ }
+ }
+
void openDevice(int deviceId) throws IOException {
mMtpManager.openDevice(deviceId);
mRootScanner.scanNow();
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
index 3afc173..27ba794 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
@@ -21,7 +21,10 @@
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbManager;
import android.mtp.MtpDevice;
+import android.mtp.MtpObjectInfo;
import android.os.ParcelFileDescriptor;
+import android.provider.DocumentsContract.Document;
+import android.provider.DocumentsContract;
import android.util.SparseArray;
import java.io.FileNotFoundException;
@@ -134,6 +137,22 @@
}
}
+ synchronized int createDocument(int deviceId, int storageId, int parentObjectHandle,
+ String mimeType, String name) throws IOException {
+ final MtpDevice device = getDevice(deviceId);
+ final MtpObjectInfo objectInfo = new MtpObjectInfo.Builder()
+ .setName(name)
+ .setStorageId(storageId)
+ .setParent(parentObjectHandle)
+ .setFormat(MtpDocument.mimeTypeToFormatType(mimeType))
+ .build();
+ final MtpObjectInfo result = device.sendObjectInfo(objectInfo);
+ if (result == null) {
+ throw new IOException("Failed to create a document");
+ }
+ return result.getObjectHandle();
+ }
+
synchronized int getParent(int deviceId, int objectHandle) throws IOException {
final MtpDevice device = getDevice(deviceId);
final int result = (int) device.getParent(objectHandle);
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java
index 5504147..1e015bd 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java
@@ -91,7 +91,8 @@
"file" + objectHandle,
new Date(),
1024,
- 0 /* thumbnail size */));
+ 0 /* thumbnail size */,
+ false /* not read only */));
}
manager.setObjectHandles(0, 0, MtpManager.OBJECT_HANDLE_ROOT_CHILDREN, childDocuments);
}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
index c1da59f..f06e2ff 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
@@ -210,7 +210,8 @@
"image.jpg" /* display name */,
new Date(1422716400000L) /* modified date */,
1024 * 1024 * 5 /* file size */,
- 1024 * 50 /* thumbnail size */));
+ 1024 * 50 /* thumbnail size */,
+ true /* read only */));
final Cursor cursor = mProvider.queryDocument("0_1_2", null);
assertEquals(1, cursor.getCount());
@@ -257,7 +258,8 @@
"image.jpg" /* display name */,
new Date(0) /* modified date */,
1024 * 1024 * 5 /* file size */,
- 1024 * 50 /* thumbnail size */));
+ 1024 * 50 /* thumbnail size */,
+ true /* read only */));
final Cursor cursor = mProvider.queryChildDocuments("0_0_0", null, null);
assertEquals(1, cursor.getCount());
@@ -302,7 +304,8 @@
"image.jpg" /* display name */,
new Date(1422716400000L) /* modified date */,
1024 * 1024 * 5 /* file size */,
- 1024 * 50 /* thumbnail size */));
+ 1024 * 50 /* thumbnail size */,
+ false /* not read only */));
mMtpManager.setParent(0, 1, 2);
mProvider.deleteDocument("0_0_1");
assertEquals(1, mResolver.getChangeCount(