Remove MtpDocument.
Change-Id: Ie4b0e55f6ff2c7b323cf767a5ed3d3c61c12734d
This commit is contained in:
@@ -18164,6 +18164,7 @@ package android.mtp {
|
||||
method public android.mtp.MtpObjectInfo.Builder setImagePixWidth(int);
|
||||
method public android.mtp.MtpObjectInfo.Builder setKeywords(java.lang.String);
|
||||
method public android.mtp.MtpObjectInfo.Builder setName(java.lang.String);
|
||||
method public android.mtp.MtpObjectInfo.Builder setObjectHandle(int);
|
||||
method public android.mtp.MtpObjectInfo.Builder setParent(int);
|
||||
method public android.mtp.MtpObjectInfo.Builder setProtectionStatus(int);
|
||||
method public android.mtp.MtpObjectInfo.Builder setSequenceNumber(int);
|
||||
|
||||
@@ -19676,6 +19676,7 @@ package android.mtp {
|
||||
method public android.mtp.MtpObjectInfo.Builder setImagePixWidth(int);
|
||||
method public android.mtp.MtpObjectInfo.Builder setKeywords(java.lang.String);
|
||||
method public android.mtp.MtpObjectInfo.Builder setName(java.lang.String);
|
||||
method public android.mtp.MtpObjectInfo.Builder setObjectHandle(int);
|
||||
method public android.mtp.MtpObjectInfo.Builder setParent(int);
|
||||
method public android.mtp.MtpObjectInfo.Builder setProtectionStatus(int);
|
||||
method public android.mtp.MtpObjectInfo.Builder setSequenceNumber(int);
|
||||
|
||||
@@ -294,6 +294,11 @@ public final class MtpObjectInfo {
|
||||
mObjectInfo.mThumbPixWidth = objectInfo.mThumbPixWidth;
|
||||
}
|
||||
|
||||
public Builder setObjectHandle(int value) {
|
||||
mObjectInfo.mHandle = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setAssociationDesc(int value) {
|
||||
mObjectInfo.mAssociationDesc = value;
|
||||
return this;
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.mtp;
|
||||
|
||||
import android.database.MatrixCursor;
|
||||
import android.mtp.MtpObjectInfo;
|
||||
import android.provider.DocumentsContract;
|
||||
import android.provider.DocumentsContract.Document;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
final class CursorHelper {
|
||||
static final int DUMMY_HANDLE_FOR_ROOT = 0;
|
||||
|
||||
private CursorHelper() {
|
||||
}
|
||||
|
||||
static void addToCursor(MtpRoot root, MatrixCursor.RowBuilder builder) {
|
||||
final Identifier identifier = new Identifier(
|
||||
root.mDeviceId, root.mStorageId, DUMMY_HANDLE_FOR_ROOT);
|
||||
builder.add(Document.COLUMN_DOCUMENT_ID, identifier.toDocumentId());
|
||||
builder.add(Document.COLUMN_DISPLAY_NAME, root.mDescription);
|
||||
builder.add(Document.COLUMN_MIME_TYPE, DocumentsContract.Document.MIME_TYPE_DIR);
|
||||
builder.add(Document.COLUMN_LAST_MODIFIED, null);
|
||||
builder.add(Document.COLUMN_FLAGS, 0);
|
||||
builder.add(Document.COLUMN_SIZE,
|
||||
(int) Math.min(root.mMaxCapacity - root.mFreeSpace, Integer.MAX_VALUE));
|
||||
}
|
||||
|
||||
static void addToCursor(MtpObjectInfo objectInfo, Identifier rootIdentifier,
|
||||
MatrixCursor.RowBuilder builder) {
|
||||
final Identifier identifier = new Identifier(
|
||||
rootIdentifier.mDeviceId, rootIdentifier.mStorageId, objectInfo.getObjectHandle());
|
||||
final String mimeType = formatTypeToMimeType(objectInfo.getFormat());
|
||||
|
||||
int flag = 0;
|
||||
if (objectInfo.getProtectionStatus() == 0) {
|
||||
flag |= DocumentsContract.Document.FLAG_SUPPORTS_DELETE |
|
||||
DocumentsContract.Document.FLAG_SUPPORTS_WRITE;
|
||||
if (mimeType == DocumentsContract.Document.MIME_TYPE_DIR) {
|
||||
flag |= DocumentsContract.Document.FLAG_DIR_SUPPORTS_CREATE;
|
||||
}
|
||||
}
|
||||
if (objectInfo.getThumbCompressedSize() > 0) {
|
||||
flag |= DocumentsContract.Document.FLAG_SUPPORTS_THUMBNAIL;
|
||||
}
|
||||
|
||||
builder.add(Document.COLUMN_DOCUMENT_ID, identifier.toDocumentId());
|
||||
builder.add(Document.COLUMN_DISPLAY_NAME, objectInfo.getName());
|
||||
builder.add(Document.COLUMN_MIME_TYPE, mimeType);
|
||||
builder.add(
|
||||
Document.COLUMN_LAST_MODIFIED,
|
||||
objectInfo.getDateModified() != 0 ? objectInfo.getDateModified() : null);
|
||||
builder.add(Document.COLUMN_FLAGS, flag);
|
||||
builder.add(Document.COLUMN_SIZE, objectInfo.getCompressedSize());
|
||||
}
|
||||
|
||||
static String formatTypeToMimeType(int format) {
|
||||
// TODO: Add complete list of mime types.
|
||||
switch (format) {
|
||||
case 0x3001:
|
||||
return DocumentsContract.Document.MIME_TYPE_DIR;
|
||||
case 0x3009:
|
||||
return "audio/mp3";
|
||||
case 0x3801:
|
||||
return "image/jpeg";
|
||||
default:
|
||||
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.
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@ package com.android.mtp;
|
||||
import android.content.ContentResolver;
|
||||
import android.database.Cursor;
|
||||
import android.database.MatrixCursor;
|
||||
import android.mtp.MtpObjectInfo;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Process;
|
||||
@@ -34,6 +35,7 @@ import java.util.LinkedList;
|
||||
* Loader for MTP document.
|
||||
* At the first request, the loader returns only first NUM_INITIAL_ENTRIES. Then it launches
|
||||
* background thread to load the rest documents and caches its result for next requests.
|
||||
* TODO: Rename this class to ObjectInfoLoader
|
||||
*/
|
||||
class DocumentLoader {
|
||||
static final int NUM_INITIAL_ENTRIES = 10;
|
||||
@@ -50,13 +52,13 @@ class DocumentLoader {
|
||||
mResolver = resolver;
|
||||
}
|
||||
|
||||
private static MtpDocument[] loadDocuments(MtpManager manager, int deviceId, int[] handles)
|
||||
private static MtpObjectInfo[] loadDocuments(MtpManager manager, int deviceId, int[] handles)
|
||||
throws IOException {
|
||||
final MtpDocument[] documents = new MtpDocument[handles.length];
|
||||
final MtpObjectInfo[] objectInfos = new MtpObjectInfo[handles.length];
|
||||
for (int i = 0; i < handles.length; i++) {
|
||||
documents[i] = manager.getDocument(deviceId, handles[i]);
|
||||
objectInfos[i] = manager.getObjectInfo(deviceId, handles[i]);
|
||||
}
|
||||
return documents;
|
||||
return objectInfos;
|
||||
}
|
||||
|
||||
synchronized Cursor queryChildDocuments(String[] columnNames, Identifier parent)
|
||||
@@ -66,7 +68,7 @@ class DocumentLoader {
|
||||
int parentHandle = parent.mObjectHandle;
|
||||
// Need to pass the special value MtpManager.OBJECT_HANDLE_ROOT_CHILDREN to
|
||||
// getObjectHandles if we would like to obtain children under the root.
|
||||
if (parentHandle == MtpDocument.DUMMY_HANDLE_FOR_ROOT) {
|
||||
if (parentHandle == CursorHelper.DUMMY_HANDLE_FOR_ROOT) {
|
||||
parentHandle = MtpManager.OBJECT_HANDLE_ROOT_CHILDREN;
|
||||
}
|
||||
task = new LoaderTask(parent, mMtpManager.getObjectHandles(
|
||||
@@ -114,16 +116,16 @@ class DocumentLoader {
|
||||
deviceId = task.mIdentifier.mDeviceId;
|
||||
handles = task.getUnloadedObjectHandles(NUM_LOADING_ENTRIES);
|
||||
}
|
||||
MtpDocument[] documents;
|
||||
MtpObjectInfo[] objectInfos;
|
||||
try {
|
||||
documents = loadDocuments(mMtpManager, deviceId, handles);
|
||||
objectInfos = loadDocuments(mMtpManager, deviceId, handles);
|
||||
} catch (IOException exception) {
|
||||
documents = null;
|
||||
objectInfos = null;
|
||||
Log.d(MtpDocumentsProvider.TAG, exception.getMessage());
|
||||
}
|
||||
synchronized (DocumentLoader.this) {
|
||||
if (documents != null) {
|
||||
task.fillDocuments(documents);
|
||||
if (objectInfos != null) {
|
||||
task.fillDocuments(objectInfos);
|
||||
final boolean shouldNotify =
|
||||
task.mLastNotified.getTime() <
|
||||
new Date().getTime() - NOTIFY_PERIOD_MS ||
|
||||
@@ -182,14 +184,14 @@ class DocumentLoader {
|
||||
private static class LoaderTask {
|
||||
final Identifier mIdentifier;
|
||||
final int[] mObjectHandles;
|
||||
final MtpDocument[] mDocuments;
|
||||
final MtpObjectInfo[] mObjectInfos;
|
||||
Date mLastNotified;
|
||||
int mNumLoaded;
|
||||
|
||||
LoaderTask(Identifier identifier, int[] objectHandles) {
|
||||
mIdentifier = identifier;
|
||||
mObjectHandles = objectHandles;
|
||||
mDocuments = new MtpDocument[mObjectHandles.length];
|
||||
mObjectInfos = new MtpObjectInfo[mObjectHandles.length];
|
||||
mNumLoaded = 0;
|
||||
mLastNotified = new Date();
|
||||
}
|
||||
@@ -199,7 +201,7 @@ class DocumentLoader {
|
||||
final Identifier rootIdentifier = new Identifier(
|
||||
mIdentifier.mDeviceId, mIdentifier.mStorageId);
|
||||
for (int i = 0; i < mNumLoaded; i++) {
|
||||
mDocuments[i].addToCursor(rootIdentifier, cursor.newRow());
|
||||
CursorHelper.addToCursor(mObjectInfos[i], rootIdentifier, cursor.newRow());
|
||||
}
|
||||
final Bundle extras = new Bundle();
|
||||
extras.putBoolean(DocumentsContract.EXTRA_LOADING, !completed());
|
||||
@@ -209,7 +211,7 @@ class DocumentLoader {
|
||||
}
|
||||
|
||||
boolean completed() {
|
||||
return mNumLoaded == mDocuments.length;
|
||||
return mNumLoaded == mObjectInfos.length;
|
||||
}
|
||||
|
||||
int[] getUnloadedObjectHandles(int count) {
|
||||
@@ -224,9 +226,9 @@ class DocumentLoader {
|
||||
mLastNotified = new Date();
|
||||
}
|
||||
|
||||
void fillDocuments(MtpDocument[] documents) {
|
||||
for (int i = 0; i < documents.length; i++) {
|
||||
mDocuments[mNumLoaded++] = documents[i];
|
||||
void fillDocuments(MtpObjectInfo[] objectInfos) {
|
||||
for (int i = 0; i < objectInfos.length; i++) {
|
||||
mObjectInfos[mNumLoaded++] = objectInfos[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ class Identifier {
|
||||
|
||||
|
||||
Identifier(int deviceId, int storageId) {
|
||||
this(deviceId, storageId, MtpDocument.DUMMY_HANDLE_FOR_ROOT);
|
||||
this(deviceId, storageId, CursorHelper.DUMMY_HANDLE_FOR_ROOT);
|
||||
}
|
||||
|
||||
Identifier(int deviceId, int storageId, int objectHandle) {
|
||||
|
||||
@@ -1,132 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.mtp;
|
||||
|
||||
import android.database.MatrixCursor;
|
||||
import android.mtp.MtpObjectInfo;
|
||||
import android.provider.DocumentsContract;
|
||||
import android.provider.DocumentsContract.Document;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
class MtpDocument {
|
||||
static final int DUMMY_HANDLE_FOR_ROOT = 0;
|
||||
|
||||
private final int mObjectHandle;
|
||||
private final int mFormat;
|
||||
private final String mName;
|
||||
private final Date mDateModified;
|
||||
private final int mSize;
|
||||
private final int mThumbSize;
|
||||
private final boolean mReadOnly;
|
||||
|
||||
/**
|
||||
* Constructor for root document.
|
||||
*/
|
||||
MtpDocument(MtpRoot root) {
|
||||
this(DUMMY_HANDLE_FOR_ROOT,
|
||||
0x3001, // Directory.
|
||||
root.mDescription,
|
||||
null, // Unknown name.
|
||||
(int) Math.min(root.mMaxCapacity - root.mFreeSpace, Integer.MAX_VALUE),
|
||||
0, // Total size.
|
||||
true); // Writable.
|
||||
}
|
||||
|
||||
MtpDocument(MtpObjectInfo objectInfo) {
|
||||
this(objectInfo.getObjectHandle(),
|
||||
objectInfo.getFormat(),
|
||||
objectInfo.getName(),
|
||||
objectInfo.getDateModified() != 0 ? new Date(objectInfo.getDateModified()) : null,
|
||||
objectInfo.getCompressedSize(),
|
||||
objectInfo.getThumbCompressedSize(),
|
||||
objectInfo.getProtectionStatus() != 0);
|
||||
}
|
||||
|
||||
MtpDocument(int objectHandle,
|
||||
int format,
|
||||
String name,
|
||||
Date dateModified,
|
||||
int size,
|
||||
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) {
|
||||
final Identifier identifier = new Identifier(
|
||||
rootIdentifier.mDeviceId, rootIdentifier.mStorageId, mObjectHandle);
|
||||
final String mimeType = formatTypeToMimeType(mFormat);
|
||||
|
||||
int flag = 0;
|
||||
if (mObjectHandle != DUMMY_HANDLE_FOR_ROOT) {
|
||||
if (mThumbSize > 0) {
|
||||
flag |= DocumentsContract.Document.FLAG_SUPPORTS_THUMBNAIL;
|
||||
}
|
||||
if (!mReadOnly) {
|
||||
flag |= DocumentsContract.Document.FLAG_SUPPORTS_DELETE |
|
||||
DocumentsContract.Document.FLAG_SUPPORTS_WRITE;
|
||||
}
|
||||
}
|
||||
if (mimeType == DocumentsContract.Document.MIME_TYPE_DIR && !mReadOnly) {
|
||||
flag |= DocumentsContract.Document.FLAG_DIR_SUPPORTS_CREATE;
|
||||
}
|
||||
|
||||
builder.add(Document.COLUMN_DOCUMENT_ID, identifier.toDocumentId());
|
||||
builder.add(Document.COLUMN_DISPLAY_NAME, mName);
|
||||
builder.add(Document.COLUMN_MIME_TYPE, mimeType);
|
||||
builder.add(
|
||||
Document.COLUMN_LAST_MODIFIED,
|
||||
mDateModified != null ? mDateModified.getTime() : null);
|
||||
builder.add(Document.COLUMN_FLAGS, flag);
|
||||
builder.add(Document.COLUMN_SIZE, mSize);
|
||||
}
|
||||
|
||||
static String formatTypeToMimeType(int format) {
|
||||
// TODO: Add complete list of mime types.
|
||||
switch (format) {
|
||||
case 0x3001:
|
||||
return DocumentsContract.Document.MIME_TYPE_DIR;
|
||||
case 0x3009:
|
||||
return "audio/mp3";
|
||||
case 0x3801:
|
||||
return "image/jpeg";
|
||||
default:
|
||||
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.
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,11 +21,12 @@ import android.content.res.AssetFileDescriptor;
|
||||
import android.database.Cursor;
|
||||
import android.database.MatrixCursor;
|
||||
import android.graphics.Point;
|
||||
import android.mtp.MtpObjectInfo;
|
||||
import android.os.CancellationSignal;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.provider.DocumentsContract;
|
||||
import android.provider.DocumentsContract.Document;
|
||||
import android.provider.DocumentsContract.Root;
|
||||
import android.provider.DocumentsContract;
|
||||
import android.provider.DocumentsProvider;
|
||||
import android.util.Log;
|
||||
|
||||
@@ -116,37 +117,37 @@ public class MtpDocumentsProvider extends DocumentsProvider {
|
||||
}
|
||||
final Identifier identifier = Identifier.createFromDocumentId(documentId);
|
||||
|
||||
MtpDocument document = null;
|
||||
if (identifier.mObjectHandle != MtpDocument.DUMMY_HANDLE_FOR_ROOT) {
|
||||
if (identifier.mObjectHandle != CursorHelper.DUMMY_HANDLE_FOR_ROOT) {
|
||||
MtpObjectInfo objectInfo;
|
||||
try {
|
||||
document = mMtpManager.getDocument(identifier.mDeviceId, identifier.mObjectHandle);
|
||||
objectInfo = mMtpManager.getObjectInfo(
|
||||
identifier.mDeviceId, identifier.mObjectHandle);
|
||||
} catch (IOException e) {
|
||||
throw new FileNotFoundException(e.getMessage());
|
||||
}
|
||||
final MatrixCursor cursor = new MatrixCursor(projection);
|
||||
CursorHelper.addToCursor(
|
||||
objectInfo,
|
||||
new Identifier(identifier.mDeviceId, identifier.mStorageId),
|
||||
cursor.newRow());
|
||||
return cursor;
|
||||
} else {
|
||||
MtpRoot[] roots;
|
||||
try {
|
||||
roots = mMtpManager.getRoots(identifier.mDeviceId);
|
||||
if (roots != null) {
|
||||
for (final MtpRoot root : roots) {
|
||||
if (identifier.mStorageId == root.mStorageId) {
|
||||
document = new MtpDocument(root);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (document == null) {
|
||||
throw new FileNotFoundException();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new FileNotFoundException(e.getMessage());
|
||||
}
|
||||
for (final MtpRoot root : roots) {
|
||||
if (identifier.mStorageId != root.mStorageId)
|
||||
continue;
|
||||
final MatrixCursor cursor = new MatrixCursor(projection);
|
||||
CursorHelper.addToCursor(root, cursor.newRow());
|
||||
return cursor;
|
||||
}
|
||||
}
|
||||
|
||||
final MatrixCursor cursor = new MatrixCursor(projection);
|
||||
document.addToCursor(
|
||||
new Identifier(identifier.mDeviceId, identifier.mStorageId), cursor.newRow());
|
||||
return cursor;
|
||||
throw new FileNotFoundException();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -225,8 +226,13 @@ public class MtpDocumentsProvider extends DocumentsProvider {
|
||||
try {
|
||||
final Identifier parentId = Identifier.createFromDocumentId(parentDocumentId);
|
||||
final int objectHandle = mMtpManager.createDocument(
|
||||
parentId.mDeviceId, parentId.mStorageId, parentId.mObjectHandle, mimeType,
|
||||
displayName);
|
||||
parentId.mDeviceId,
|
||||
new MtpObjectInfo.Builder()
|
||||
.setStorageId(parentId.mStorageId)
|
||||
.setParent(parentId.mObjectHandle)
|
||||
.setFormat(CursorHelper.mimeTypeToFormatType(mimeType))
|
||||
.setName(displayName)
|
||||
.build());
|
||||
final String documentId = new Identifier(parentId.mDeviceId, parentId.mStorageId,
|
||||
objectHandle).toDocumentId();
|
||||
notifyChildDocumentsChange(parentDocumentId);
|
||||
|
||||
@@ -108,16 +108,12 @@ class MtpManager {
|
||||
return results;
|
||||
}
|
||||
|
||||
synchronized MtpObjectInfo getObjectInfo(int deviceId, int objectHandle) throws IOException {
|
||||
synchronized MtpObjectInfo getObjectInfo(int deviceId, int objectHandle)
|
||||
throws IOException {
|
||||
final MtpDevice device = getDevice(deviceId);
|
||||
return device.getObjectInfo(objectHandle);
|
||||
}
|
||||
|
||||
synchronized MtpDocument getDocument(int deviceId, int objectHandle) throws IOException {
|
||||
final MtpDevice device = getDevice(deviceId);
|
||||
return new MtpDocument(device.getObjectInfo(objectHandle));
|
||||
}
|
||||
|
||||
synchronized int[] getObjectHandles(int deviceId, int storageId, int parentObjectHandle)
|
||||
throws IOException {
|
||||
final MtpDevice device = getDevice(deviceId);
|
||||
@@ -142,18 +138,6 @@ class MtpManager {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Remove this method.
|
||||
synchronized int createDocument(int deviceId, int storageId, int parentObjectHandle,
|
||||
String mimeType, String name) throws IOException {
|
||||
final MtpObjectInfo objectInfo = new MtpObjectInfo.Builder()
|
||||
.setName(name)
|
||||
.setStorageId(storageId)
|
||||
.setParent(parentObjectHandle)
|
||||
.setFormat(MtpDocument.mimeTypeToFormatType(mimeType))
|
||||
.build();
|
||||
return createDocument(deviceId, objectInfo);
|
||||
}
|
||||
|
||||
synchronized int createDocument(int deviceId, MtpObjectInfo objectInfo) throws IOException {
|
||||
final MtpDevice device = getDevice(deviceId);
|
||||
final MtpObjectInfo result = device.sendObjectInfo(objectInfo);
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.mtp;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.mtp.MtpObjectInfo;
|
||||
import android.net.Uri;
|
||||
import android.provider.DocumentsContract;
|
||||
import android.test.AndroidTestCase;
|
||||
@@ -31,14 +32,14 @@ import java.util.concurrent.CountDownLatch;
|
||||
|
||||
@SmallTest
|
||||
public class DocumentLoaderTest extends AndroidTestCase {
|
||||
private BlockableTestMtpMaanger mManager;
|
||||
private BlockableTestMtpManager mManager;
|
||||
private TestContentResolver mResolver;
|
||||
private DocumentLoader mLoader;
|
||||
final private Identifier mParentIdentifier = new Identifier(0, 0, 0);
|
||||
|
||||
@Override
|
||||
public void setUp() {
|
||||
mManager = new BlockableTestMtpMaanger(getContext());
|
||||
mManager = new BlockableTestMtpManager(getContext());
|
||||
mResolver = new TestContentResolver();
|
||||
mLoader = new DocumentLoader(mManager, mResolver);
|
||||
}
|
||||
@@ -85,22 +86,17 @@ public class DocumentLoaderTest extends AndroidTestCase {
|
||||
for (int i = 0; i < childDocuments.length; i++) {
|
||||
final int objectHandle = i + 1;
|
||||
childDocuments[i] = objectHandle;
|
||||
manager.setDocument(0, objectHandle, new MtpDocument(
|
||||
objectHandle,
|
||||
0 /* format */,
|
||||
"file" + objectHandle,
|
||||
new Date(),
|
||||
1024,
|
||||
0 /* thumbnail size */,
|
||||
false /* not read only */));
|
||||
manager.setObjectInfo(0, new MtpObjectInfo.Builder()
|
||||
.setObjectHandle(objectHandle)
|
||||
.build());
|
||||
}
|
||||
manager.setObjectHandles(0, 0, MtpManager.OBJECT_HANDLE_ROOT_CHILDREN, childDocuments);
|
||||
}
|
||||
|
||||
private static class BlockableTestMtpMaanger extends TestMtpManager {
|
||||
private static class BlockableTestMtpManager extends TestMtpManager {
|
||||
final private Map<String, CountDownLatch> blockedDocuments = new HashMap<>();
|
||||
|
||||
BlockableTestMtpMaanger(Context context) {
|
||||
BlockableTestMtpManager(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@@ -113,7 +109,7 @@ public class DocumentLoaderTest extends AndroidTestCase {
|
||||
}
|
||||
|
||||
@Override
|
||||
MtpDocument getDocument(int deviceId, int objectHandle) throws IOException {
|
||||
MtpObjectInfo getObjectInfo(int deviceId, int objectHandle) throws IOException {
|
||||
final CountDownLatch latch = blockedDocuments.get(pack(deviceId, objectHandle));
|
||||
if (latch != null) {
|
||||
try {
|
||||
@@ -122,7 +118,7 @@ public class DocumentLoaderTest extends AndroidTestCase {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
return super.getDocument(deviceId, objectHandle);
|
||||
return super.getObjectInfo(deviceId, objectHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,9 +17,12 @@
|
||||
package com.android.mtp;
|
||||
|
||||
import android.database.Cursor;
|
||||
import android.mtp.MtpConstants;
|
||||
import android.mtp.MtpObjectInfo.Builder;
|
||||
import android.mtp.MtpObjectInfo;
|
||||
import android.net.Uri;
|
||||
import android.provider.DocumentsContract;
|
||||
import android.provider.DocumentsContract.Root;
|
||||
import android.provider.DocumentsContract;
|
||||
import android.test.AndroidTestCase;
|
||||
import android.test.suitebuilder.annotation.SmallTest;
|
||||
|
||||
@@ -204,14 +207,14 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
|
||||
}
|
||||
|
||||
public void testQueryDocument() throws IOException {
|
||||
mMtpManager.setDocument(0, 2, new MtpDocument(
|
||||
2 /* object handle */,
|
||||
0x3801 /* JPEG */,
|
||||
"image.jpg" /* display name */,
|
||||
new Date(1422716400000L) /* modified date */,
|
||||
1024 * 1024 * 5 /* file size */,
|
||||
1024 * 50 /* thumbnail size */,
|
||||
false /* read only */));
|
||||
mMtpManager.setObjectInfo(0, new MtpObjectInfo.Builder()
|
||||
.setObjectHandle(2)
|
||||
.setFormat(0x3801)
|
||||
.setName("image.jpg")
|
||||
.setDateModified(1422716400000L)
|
||||
.setCompressedSize(1024 * 1024 * 5)
|
||||
.setThumbCompressedSize(1024 * 50)
|
||||
.build());
|
||||
final Cursor cursor = mProvider.queryDocument("0_1_2", null);
|
||||
assertEquals(1, cursor.getCount());
|
||||
|
||||
@@ -229,14 +232,12 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
|
||||
}
|
||||
|
||||
public void testQueryDocument_directory() throws IOException {
|
||||
mMtpManager.setDocument(0, 2, new MtpDocument(
|
||||
2 /* object handle */,
|
||||
0x3001 /* directory */,
|
||||
"directory" /* display name */,
|
||||
new Date(1422716400000L) /* modified date */,
|
||||
0 /* file size */,
|
||||
0 /* thumbnail size */,
|
||||
false /* read only */));
|
||||
mMtpManager.setObjectInfo(0, new MtpObjectInfo.Builder()
|
||||
.setObjectHandle(2)
|
||||
.setFormat(0x3001 /* directory format */)
|
||||
.setName("directory")
|
||||
.setDateModified(1422716400000L)
|
||||
.build());
|
||||
final Cursor cursor = mProvider.queryDocument("0_1_2", null);
|
||||
assertEquals(1, cursor.getCount());
|
||||
|
||||
@@ -278,14 +279,14 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
|
||||
public void testQueryChildDocuments() throws Exception {
|
||||
mMtpManager.setObjectHandles(0, 0, -1, new int[] { 1 });
|
||||
|
||||
mMtpManager.setDocument(0, 1, new MtpDocument(
|
||||
1 /* object handle */,
|
||||
0x3801 /* JPEG */,
|
||||
"image.jpg" /* display name */,
|
||||
new Date(0) /* modified date */,
|
||||
1024 * 1024 * 5 /* file size */,
|
||||
1024 * 50 /* thumbnail size */,
|
||||
true /* read only */));
|
||||
mMtpManager.setObjectInfo(0, new MtpObjectInfo.Builder()
|
||||
.setObjectHandle(1)
|
||||
.setFormat(0x3801 /* JPEG */)
|
||||
.setName("image.jpg")
|
||||
.setCompressedSize(1024 * 1024 * 5)
|
||||
.setThumbCompressedSize(5 * 1024)
|
||||
.setProtectionStatus(MtpConstants.PROTECTION_STATUS_READ_ONLY)
|
||||
.build());
|
||||
|
||||
final Cursor cursor = mProvider.queryChildDocuments("0_0_0", null, null);
|
||||
assertEquals(1, cursor.getCount());
|
||||
@@ -321,14 +322,14 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
|
||||
}
|
||||
|
||||
public void testDeleteDocument() throws FileNotFoundException {
|
||||
mMtpManager.setDocument(0, 1, new MtpDocument(
|
||||
1 /* object handle */,
|
||||
0x3801 /* JPEG */,
|
||||
"image.jpg" /* display name */,
|
||||
new Date(1422716400000L) /* modified date */,
|
||||
1024 * 1024 * 5 /* file size */,
|
||||
1024 * 50 /* thumbnail size */,
|
||||
false /* not read only */));
|
||||
mMtpManager.setObjectInfo(0, new MtpObjectInfo.Builder()
|
||||
.setObjectHandle(1)
|
||||
.setFormat(0x3801)
|
||||
.setName("image.jpg")
|
||||
.setDateModified(1422716400000L)
|
||||
.setCompressedSize(1024 * 1024 * 5)
|
||||
.setThumbCompressedSize(1024 * 50)
|
||||
.build());
|
||||
mMtpManager.setParent(0, 1, 2);
|
||||
mProvider.deleteDocument("0_0_1");
|
||||
assertEquals(1, mResolver.getChangeCount(
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.mtp;
|
||||
|
||||
import android.mtp.MtpObjectInfo;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.test.AndroidTestCase;
|
||||
import android.test.suitebuilder.annotation.SmallTest;
|
||||
@@ -56,7 +57,9 @@ public class PipeManagerTest extends AndroidTestCase {
|
||||
|
||||
public void testWriteDocument_basic() throws Exception {
|
||||
// Create a placeholder file which should be replaced by a real file later.
|
||||
mtpManager.setDocument(0, 1, new MtpDocument(1, 0, "", new Date(), 0, 0, false));
|
||||
mtpManager.setObjectInfo(0, new MtpObjectInfo.Builder()
|
||||
.setObjectHandle(1)
|
||||
.build());
|
||||
|
||||
// Upload testing bytes.
|
||||
final ParcelFileDescriptor descriptor = mPipeManager.writeDocument(
|
||||
@@ -69,14 +72,14 @@ public class PipeManagerTest extends AndroidTestCase {
|
||||
|
||||
// Check if the placeholder file is removed.
|
||||
try {
|
||||
final MtpDocument placeholderDocument = mtpManager.getDocument(0, 1);
|
||||
final MtpObjectInfo placeholderDocument = mtpManager.getObjectInfo(0, 1);
|
||||
fail(); // The placeholder file has not been deleted.
|
||||
} catch (IOException e) {
|
||||
// Expected error, as the file is gone.
|
||||
}
|
||||
|
||||
// Confirm that the target file is created.
|
||||
final MtpDocument targetDocument = mtpManager.getDocument(
|
||||
final MtpObjectInfo targetDocument = mtpManager.getObjectInfo(
|
||||
0, TestMtpManager.CREATED_DOCUMENT_HANDLE);
|
||||
assertTrue(targetDocument != null);
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ public class TestMtpManager extends MtpManager {
|
||||
private final Set<Integer> mValidDevices = new HashSet<>();
|
||||
private final Set<Integer> mOpenedDevices = new TreeSet<>();
|
||||
private final Map<Integer, MtpRoot[]> mRoots = new HashMap<>();
|
||||
private final Map<String, MtpDocument> mDocuments = new HashMap<>();
|
||||
private final Map<String, MtpObjectInfo> mObjectInfos = new HashMap<>();
|
||||
private final Map<String, int[]> mObjectHandles = new HashMap<>();
|
||||
private final Map<String, byte[]> mThumbnailBytes = new HashMap<>();
|
||||
private final Map<String, Integer> mParents = new HashMap<>();
|
||||
@@ -54,16 +54,16 @@ public class TestMtpManager extends MtpManager {
|
||||
mValidDevices.add(deviceId);
|
||||
}
|
||||
|
||||
void setObjectHandles(int deviceId, int storageId, int objectHandle, int[] documents) {
|
||||
mObjectHandles.put(pack(deviceId, storageId, objectHandle), documents);
|
||||
void setObjectHandles(int deviceId, int storageId, int parentHandle, int[] objectHandles) {
|
||||
mObjectHandles.put(pack(deviceId, storageId, parentHandle), objectHandles);
|
||||
}
|
||||
|
||||
void setRoots(int deviceId, MtpRoot[] roots) {
|
||||
mRoots.put(deviceId, roots);
|
||||
}
|
||||
|
||||
void setDocument(int deviceId, int objectHandle, MtpDocument document) {
|
||||
mDocuments.put(pack(deviceId, objectHandle), document);
|
||||
void setObjectInfo(int deviceId, MtpObjectInfo objectInfo) {
|
||||
mObjectInfos.put(pack(deviceId, objectInfo.getObjectHandle()), objectInfo);
|
||||
}
|
||||
|
||||
void setImportFileBytes(int deviceId, int objectHandle, byte[] bytes) {
|
||||
@@ -78,6 +78,8 @@ public class TestMtpManager extends MtpManager {
|
||||
mThumbnailBytes.put(pack(deviceId, objectHandle), bytes);
|
||||
}
|
||||
|
||||
// TODO: Remove this method, as MtpObjectInfo contains information about
|
||||
// parents.
|
||||
void setParent(int deviceId, int objectHandle, int parentObjectHandle) {
|
||||
mParents.put(pack(deviceId, objectHandle), parentObjectHandle);
|
||||
}
|
||||
@@ -107,23 +109,14 @@ public class TestMtpManager extends MtpManager {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
MtpDocument getDocument(int deviceId, int objectHandle) throws IOException {
|
||||
final String key = pack(deviceId, objectHandle);
|
||||
if (mDocuments.containsKey(key)) {
|
||||
return mDocuments.get(key);
|
||||
} else {
|
||||
throw new IOException("getDocument error: " + key);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
MtpObjectInfo getObjectInfo(int deviceId, int objectHandle) throws IOException {
|
||||
final MtpDocument document = getDocument(deviceId, objectHandle);
|
||||
// It's impossible to set an object id of MtpObjectInfo at this stage. Also,
|
||||
// it's hard to get any information from MtpDocument, as it's designed to return them
|
||||
// only via cursors. Rework these.
|
||||
return new MtpObjectInfo.Builder().build();
|
||||
final String key = pack(deviceId, objectHandle);
|
||||
if (mObjectInfos.containsKey(key)) {
|
||||
return mObjectInfos.get(key);
|
||||
} else {
|
||||
throw new IOException("getObjectInfo error: " + key);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -152,18 +145,9 @@ public class TestMtpManager extends MtpManager {
|
||||
|
||||
@Override
|
||||
int createDocument(int deviceId, MtpObjectInfo objectInfo) throws IOException {
|
||||
// For simplicity, it allows to create only one document, and it always has the hardcoded
|
||||
// CREATED_DOCUMENT_HANDLE document handle.
|
||||
final String key = pack(deviceId, CREATED_DOCUMENT_HANDLE);
|
||||
if (!mDocuments.containsKey(key)) {
|
||||
mDocuments.put(key, new MtpDocument(
|
||||
CREATED_DOCUMENT_HANDLE,
|
||||
objectInfo.getFormat(),
|
||||
objectInfo.getName(),
|
||||
new Date(objectInfo.getDateModified()),
|
||||
objectInfo.getCompressedSize(),
|
||||
objectInfo.getThumbCompressedSize(),
|
||||
false /* Always writable for testing. */));
|
||||
if (!mObjectInfos.containsKey(key)) {
|
||||
mObjectInfos.put(key, objectInfo);
|
||||
} else {
|
||||
throw new IOException();
|
||||
}
|
||||
@@ -174,7 +158,7 @@ public class TestMtpManager extends MtpManager {
|
||||
void sendObject(int deviceId, int objectHandle, int size, ParcelFileDescriptor source)
|
||||
throws IOException {
|
||||
final String key = pack(deviceId, objectHandle);
|
||||
if (!mDocuments.containsKey(key)) {
|
||||
if (!mObjectInfos.containsKey(key)) {
|
||||
throw new IOException();
|
||||
}
|
||||
|
||||
@@ -201,8 +185,8 @@ public class TestMtpManager extends MtpManager {
|
||||
@Override
|
||||
void deleteDocument(int deviceId, int objectHandle) throws IOException {
|
||||
final String key = pack(deviceId, objectHandle);
|
||||
if (mDocuments.containsKey(key)) {
|
||||
mDocuments.remove(key);
|
||||
if (mObjectInfos.containsKey(key)) {
|
||||
mObjectInfos.remove(key);
|
||||
} else {
|
||||
throw new IOException();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user