The structure of files in MtpDocumentsProvider looks like
/device/storage/files. But MtpDocumentsProvider shows files
just under the device if the device has only single storage.
It causes a problem that MtpDocumentsProvider tries to create a file
under the device. Previously it tries to create a file with storageId =
0, which means MTP device choose a storage to store the file.
Because it only happens when the device has a single storage, the file
is properly written to the device. But the database in
MtpDocumentsProvider goes into the illegal state where the file is
placed just under the device.
Bug:
32561572
Test: adb shell am instrument -w -e class com.android.mtp.MtpDocumentsProviderTest com.android.mtp.tests/com.android.mtp.TestResultInstrumentation
Change-Id: I47a373ceee8a64ba9995934317693e79d2497ee0
throw new UnsupportedOperationException(
"Writing operation is not supported by the device.");
}
+
+ final int parentObjectHandle;
+ final int storageId;
+ switch (parentId.mDocumentType) {
+ case MtpDatabaseConstants.DOCUMENT_TYPE_DEVICE:
+ final String[] storageDocumentIds =
+ mDatabase.getStorageDocumentIds(parentId.mDocumentId);
+ if (storageDocumentIds.length == 1) {
+ final String newDocumentId =
+ createDocument(storageDocumentIds[0], mimeType, displayName);
+ notifyChildDocumentsChange(parentDocumentId);
+ return newDocumentId;
+ } else {
+ throw new UnsupportedOperationException(
+ "Cannot create a file under the device.");
+ }
+ case MtpDatabaseConstants.DOCUMENT_TYPE_STORAGE:
+ storageId = parentId.mStorageId;
+ parentObjectHandle = -1;
+ break;
+ case MtpDatabaseConstants.DOCUMENT_TYPE_OBJECT:
+ storageId = parentId.mStorageId;
+ parentObjectHandle = parentId.mObjectHandle;
+ break;
+ default:
+ throw new IllegalArgumentException("Unexpected document type.");
+ }
+
pipe = ParcelFileDescriptor.createReliablePipe();
int objectHandle = -1;
MtpObjectInfo info = null;
MtpConstants.FORMAT_ASSOCIATION :
MediaFile.getFormatCode(displayName, mimeType);
info = new MtpObjectInfo.Builder()
- .setStorageId(parentId.mStorageId)
- .setParent(parentId.mObjectHandle)
+ .setStorageId(storageId)
+ .setParent(parentObjectHandle)
.setFormat(formatCode)
.setName(displayName)
.build();
public void testOpenDocument_writing() throws Exception {
setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
setupRoots(0, new MtpRoot[] {
- new MtpRoot(0, 0, "Storage", 0, 0, "")
+ new MtpRoot(0, 100, "Storage", 0, 0, "")
});
final String documentId = mProvider.createDocument("2", "text/plain", "test.txt");
{
}
}
+ public void testCreateDocument() throws Exception {
+ setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
+ setupRoots(0, new MtpRoot[] {
+ new MtpRoot(0, 100, "Storage A", 100, 100, null)
+ });
+ final String documentId = mProvider.createDocument("1", "text/plain", "note.txt");
+ final Uri deviceUri = DocumentsContract.buildChildDocumentsUri(
+ MtpDocumentsProvider.AUTHORITY, "1");
+ final Uri storageUri = DocumentsContract.buildChildDocumentsUri(
+ MtpDocumentsProvider.AUTHORITY, "2");
+ mResolver.waitForNotification(storageUri, 1);
+ mResolver.waitForNotification(deviceUri, 1);
+ try (final Cursor cursor = mProvider.queryDocument(documentId, null)) {
+ assertTrue(cursor.moveToNext());
+ assertEquals(
+ "note.txt",
+ cursor.getString(cursor.getColumnIndex(Document.COLUMN_DISPLAY_NAME)));
+ assertEquals(
+ "text/plain",
+ cursor.getString(cursor.getColumnIndex(Document.COLUMN_MIME_TYPE)));
+ }
+ }
+
public void testCreateDocument_noWritingSupport() throws Exception {
setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
mMtpManager.addValidDevice(new MtpDeviceRecord(
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
+import junit.framework.Assert;
public class TestMtpManager extends MtpManager {
public static final int CREATED_DOCUMENT_HANDLE = 1000;
@Override
int createDocument(int deviceId, MtpObjectInfo objectInfo, ParcelFileDescriptor source)
throws IOException {
+ Assert.assertNotSame(0, objectInfo.getStorageId());
+ Assert.assertNotSame(-1, objectInfo.getStorageId());
+ Assert.assertNotSame(0, objectInfo.getParent());
final String key = pack(deviceId, CREATED_DOCUMENT_HANDLE);
if (mObjectInfos.containsKey(key)) {
throw new IOException();