Loading packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java +17 −0 Original line number Diff line number Diff line Loading @@ -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, Loading packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java +1 −1 Original line number Diff line number Diff line Loading @@ -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); } } Loading packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java +24 −9 Original line number Diff line number Diff line Loading @@ -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; } Loading @@ -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(); } Loading Loading @@ -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 Loading @@ -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( Loading Loading @@ -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()); Loading packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java +2 −10 Original line number Diff line number Diff line Loading @@ -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); } } packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java +30 −9 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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 { Loading @@ -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. Loading @@ -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); Loading @@ -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]; Loading @@ -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(); Loading Loading
packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java +17 −0 Original line number Diff line number Diff line Loading @@ -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, Loading
packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java +1 −1 Original line number Diff line number Diff line Loading @@ -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); } } Loading
packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java +24 −9 Original line number Diff line number Diff line Loading @@ -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; } Loading @@ -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(); } Loading Loading @@ -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 Loading @@ -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( Loading Loading @@ -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()); Loading
packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java +2 −10 Original line number Diff line number Diff line Loading @@ -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); } }
packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java +30 −9 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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 { Loading @@ -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. Loading @@ -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); Loading @@ -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]; Loading @@ -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(); Loading