diff options
| author | 2016-02-19 18:05:42 +0900 | |
|---|---|---|
| committer | 2016-02-19 18:05:42 +0900 | |
| commit | f578fa275a535016f5322c88ad7a92e517d04a12 (patch) | |
| tree | 5086c2749a77d45f940ec8a42cff8a3740ac028a | |
| parent | dd6e4c19842c83778efda0e4887854fc121e9faa (diff) | |
Update object info when writing a file.
The MTP spec does not offer a way to update bytes of exisitng files, so
our provider implementation creates a new file with new bytes and
removes old one.
Previously the new file uses new document ID and the exising document ID
is expired. Also the provider does not update the metadata
database. Thus users see the old flie in DocumentsUI but actually the
files is not accessible.
The CL updates the database with exisitng document ID, so that we can
access the new file with exisiting document ID.
BUG=26549400
Change-Id: I629b707a2e662b34625e8b28857ef818d8933996
7 files changed, 94 insertions, 32 deletions
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java index 441b9a774ac3..ca5c79974d4d 100644 --- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java +++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java @@ -581,6 +581,23 @@ class MtpDatabase { } } + void updateObject(String documentId, int deviceId, String parentId, MtpObjectInfo info) { + final ContentValues values = new ContentValues(); + getObjectDocumentValues(values, deviceId, parentId, info); + + mDatabase.beginTransaction(); + try { + mDatabase.update( + TABLE_DOCUMENTS, + values, + Document.COLUMN_DOCUMENT_ID + " = ?", + strings(documentId)); + mDatabase.setTransactionSuccessful(); + } finally { + mDatabase.endTransaction(); + } + } + private static class OpenHelper extends SQLiteOpenHelper { public OpenHelper(Context context, int flags) { super(context, diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java index db1671d6296a..d329e3cdd375 100644 --- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java +++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java @@ -486,7 +486,7 @@ public class MtpDocumentsProvider extends DocumentsProvider { public final DocumentLoader mDocumentLoader; public DeviceToolkit(MtpManager manager, ContentResolver resolver, MtpDatabase database) { - mPipeManager = new PipeManager(); + mPipeManager = new PipeManager(database); mDocumentLoader = new DocumentLoader(manager, resolver, database); } } diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java index 16523bca454c..645bfcd3eeb4 100644 --- a/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java +++ b/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java @@ -29,12 +29,14 @@ import java.util.concurrent.Executors; class PipeManager { final ExecutorService mExecutor; + final MtpDatabase mDatabase; - PipeManager() { - this(Executors.newSingleThreadExecutor()); + PipeManager(MtpDatabase database) { + this(database, Executors.newSingleThreadExecutor()); } - PipeManager(ExecutorService executor) { + PipeManager(MtpDatabase database, ExecutorService executor) { + this.mDatabase = database; this.mExecutor = executor; } @@ -46,7 +48,7 @@ class PipeManager { ParcelFileDescriptor writeDocument(Context context, MtpManager model, Identifier identifier) throws IOException { - final Task task = new WriteDocumentTask(context, model, identifier); + final Task task = new WriteDocumentTask(context, model, identifier, mDatabase); mExecutor.execute(task); return task.getWritingFileDescriptor(); } @@ -100,11 +102,14 @@ class PipeManager { private static class WriteDocumentTask extends Task { private final Context mContext; + private final MtpDatabase mDatabase; - WriteDocumentTask(Context context, MtpManager model, Identifier identifier) + WriteDocumentTask( + Context context, MtpManager model, Identifier identifier, MtpDatabase database) throws IOException { super(model, identifier); mContext = context; + mDatabase = database; } @Override @@ -112,7 +117,7 @@ class PipeManager { File tempFile = null; try { // Obtain a temporary file and copy the data to it. - tempFile = mContext.getCacheDir().createTempFile("mtp", "tmp"); + tempFile = File.createTempFile("mtp", "tmp", mContext.getCacheDir()); try ( final FileOutputStream tempOutputStream = new ParcelFileDescriptor.AutoCloseOutputStream( @@ -140,12 +145,22 @@ class PipeManager { // Create the target object info with a correct file size and upload the file. final MtpObjectInfo targetObjectInfo = new MtpObjectInfo.Builder(placeholderObjectInfo) - .setCompressedSize((int) tempFile.length()) + .setCompressedSize(tempFile.length()) .build(); final ParcelFileDescriptor tempInputDescriptor = ParcelFileDescriptor.open( tempFile, ParcelFileDescriptor.MODE_READ_ONLY); - mManager.createDocument(mIdentifier.mDeviceId, - targetObjectInfo, tempInputDescriptor); + final int newObjectHandle = mManager.createDocument( + mIdentifier.mDeviceId, targetObjectInfo, tempInputDescriptor); + + final MtpObjectInfo newObjectInfo = mManager.getObjectInfo( + mIdentifier.mDeviceId, newObjectHandle); + final Identifier parentIdentifier = + mDatabase.getParentIdentifier(mIdentifier.mDocumentId); + mDatabase.updateObject( + mIdentifier.mDocumentId, + mIdentifier.mDeviceId, + parentIdentifier.mDocumentId, + newObjectInfo); } catch (IOException error) { Log.w(MtpDocumentsProvider.TAG, "Failed to send a file because of: " + error.getMessage()); diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java index 1df7351a8446..05c9c57e2409 100644 --- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java +++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java @@ -983,18 +983,10 @@ public class MtpDatabaseTest extends AndroidTestCase { } private void addTestDevice() throws FileNotFoundException { - mDatabase.getMapper().startAddingDocuments(null); - mDatabase.getMapper().putDeviceDocument(new MtpDeviceRecord( - 0, "Device", "device_key", /* opened is */ true, new MtpRoot[0], null, - null)); - mDatabase.getMapper().stopAddingDocuments(null); + TestUtil.addTestDevice(mDatabase); } private void addTestStorage(String parentId) throws FileNotFoundException { - mDatabase.getMapper().startAddingDocuments(parentId); - mDatabase.getMapper().putStorageDocuments(parentId, new MtpRoot[] { - new MtpRoot(0, 100, "Storage", 1024, 1024, ""), - }); - mDatabase.getMapper().stopAddingDocuments(parentId); + TestUtil.addTestStorage(mDatabase, parentId); } } diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java index 4dfc785a54ec..94f87ffe55ad 100644 --- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java +++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java @@ -16,8 +16,10 @@ package com.android.mtp; +import android.database.Cursor; import android.mtp.MtpObjectInfo; import android.os.ParcelFileDescriptor; +import android.provider.DocumentsContract.Document; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.MediumTest; @@ -33,12 +35,14 @@ public class PipeManagerTest extends AndroidTestCase { private TestMtpManager mtpManager; private ExecutorService mExecutor; private PipeManager mPipeManager; + private MtpDatabase mDatabase; @Override public void setUp() { mtpManager = new TestMtpManager(getContext()); mExecutor = Executors.newSingleThreadExecutor(); - mPipeManager = new PipeManager(mExecutor); + mDatabase = new MtpDatabase(getContext(), MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY); + mPipeManager = new PipeManager(mDatabase, mExecutor); } public void testReadDocument_basic() throws Exception { @@ -57,25 +61,32 @@ public class PipeManagerTest extends AndroidTestCase { } public void testWriteDocument_basic() throws Exception { + TestUtil.addTestDevice(mDatabase); + TestUtil.addTestStorage(mDatabase, "1"); + + final MtpObjectInfo info = + new MtpObjectInfo.Builder().setObjectHandle(1).setName("note.txt").build(); + mDatabase.getMapper().startAddingDocuments("2"); + mDatabase.getMapper().putChildDocuments(0, "2", new MtpObjectInfo[] { info }); + mDatabase.getMapper().stopAddingDocuments("2"); // Create a placeholder file which should be replaced by a real file later. - mtpManager.setObjectInfo(0, new MtpObjectInfo.Builder() - .setObjectHandle(1) - .build()); + mtpManager.setObjectInfo(0, info); // Upload testing bytes. final ParcelFileDescriptor descriptor = mPipeManager.writeDocument( getContext(), mtpManager, - new Identifier(0, 0, 1, null, MtpDatabaseConstants.DOCUMENT_TYPE_OBJECT)); + new Identifier(0, 0, 1, "2", MtpDatabaseConstants.DOCUMENT_TYPE_OBJECT)); final ParcelFileDescriptor.AutoCloseOutputStream outputStream = new ParcelFileDescriptor.AutoCloseOutputStream(descriptor); outputStream.write(HELLO_BYTES, 0, HELLO_BYTES.length); outputStream.close(); - mExecutor.awaitTermination(1000, TimeUnit.MILLISECONDS); + mExecutor.shutdown(); + assertTrue(mExecutor.awaitTermination(1000, TimeUnit.MILLISECONDS)); // Check if the placeholder file is removed. try { - final MtpObjectInfo placeholderDocument = mtpManager.getObjectInfo(0, 1); + mtpManager.getObjectInfo(0, 1); fail(); // The placeholder file has not been deleted. } catch (IOException e) { // Expected error, as the file is gone. @@ -86,6 +97,14 @@ public class PipeManagerTest extends AndroidTestCase { 0, TestMtpManager.CREATED_DOCUMENT_HANDLE); assertTrue(targetDocument != null); + // Confirm the object handle is updated. + try (final Cursor cursor = mDatabase.queryDocument( + "2", new String[] { MtpDatabaseConstants.COLUMN_OBJECT_HANDLE })) { + assertEquals(1, cursor.getCount()); + cursor.moveToNext(); + assertEquals(TestMtpManager.CREATED_DOCUMENT_HANDLE, cursor.getInt(0)); + } + // Verify uploaded bytes. final byte[] uploadedBytes = mtpManager.getImportFileBytes( 0, TestMtpManager.CREATED_DOCUMENT_HANDLE); @@ -112,7 +131,8 @@ public class PipeManagerTest extends AndroidTestCase { private void assertDescriptor(ParcelFileDescriptor descriptor, byte[] expectedBytes) throws IOException, InterruptedException { - mExecutor.awaitTermination(1000, TimeUnit.MILLISECONDS); + mExecutor.shutdown(); + assertTrue(mExecutor.awaitTermination(1000, TimeUnit.MILLISECONDS)); try (final ParcelFileDescriptor.AutoCloseInputStream stream = new ParcelFileDescriptor.AutoCloseInputStream(descriptor)) { byte[] results = new byte[100]; @@ -125,7 +145,8 @@ public class PipeManagerTest extends AndroidTestCase { private void assertDescriptorError(ParcelFileDescriptor descriptor) throws InterruptedException { - mExecutor.awaitTermination(1000, TimeUnit.MILLISECONDS); + mExecutor.shutdown(); + assertTrue(mExecutor.awaitTermination(1000, TimeUnit.MILLISECONDS)); try { descriptor.checkError(); fail(); diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java index 43781520aec5..1b46f3c62aa1 100644 --- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java +++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java @@ -149,7 +149,9 @@ public class TestMtpManager extends MtpManager { if (mObjectInfos.containsKey(key)) { throw new IOException(); } - mObjectInfos.put(key, objectInfo); + final MtpObjectInfo newInfo = new MtpObjectInfo.Builder(objectInfo). + setObjectHandle(CREATED_DOCUMENT_HANDLE).build(); + mObjectInfos.put(key, newInfo); if (objectInfo.getFormat() != 0x3001) { try (final ParcelFileDescriptor.AutoCloseInputStream inputStream = new ParcelFileDescriptor.AutoCloseInputStream(source)) { diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestUtil.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestUtil.java index ffcc0882e019..34dd77bd3747 100644 --- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestUtil.java +++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestUtil.java @@ -21,12 +21,11 @@ import android.hardware.usb.UsbDeviceConnection; import android.hardware.usb.UsbManager; import android.os.SystemClock; +import java.io.FileNotFoundException; import java.io.IOException; import java.util.HashMap; import java.util.Objects; -import junit.framework.Assert; - /** * Static utility methods for testing. */ @@ -57,6 +56,22 @@ final class TestUtil { } } + static void addTestDevice(MtpDatabase database) throws FileNotFoundException { + database.getMapper().startAddingDocuments(null); + database.getMapper().putDeviceDocument(new MtpDeviceRecord( + 0, "Device", "device_key", /* opened is */ true, new MtpRoot[0], null, + null)); + database.getMapper().stopAddingDocuments(null); + } + + static void addTestStorage(MtpDatabase database, String parentId) throws FileNotFoundException { + database.getMapper().startAddingDocuments(parentId); + database.getMapper().putStorageDocuments(parentId, new MtpRoot[] { + new MtpRoot(0, 100, "Storage", 1024, 1024, ""), + }); + database.getMapper().stopAddingDocuments(parentId); + } + private static UsbDevice findMtpDevice( UsbManager usbManager, MtpManager manager) throws IOException { |