Merge "Update object info when writing a file." into nyc-dev
am: 073f5aaec7
* commit '073f5aaec7256a693dbe09489ddd433ea8267898':
Update object info when writing a file.
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user