Loading packages/MtpDocumentsProvider/src/com/android/mtp/Identifier.java +35 −5 Original line number Diff line number Diff line Loading @@ -19,14 +19,44 @@ package com.android.mtp; /** * Static utilities for ID. */ abstract class Identifier { class Identifier { int mDeviceId; int mStorageId; int mObjectHandle; static Identifier createFromRootId(String rootId) { final String[] components = rootId.split(":"); return new Identifier( Integer.parseInt(components[0]), Integer.parseInt(components[1])); } static Identifier createFromDocumentId(String documentId) { final String[] components = documentId.split(":"); return new Identifier( Integer.parseInt(components[0]), Integer.parseInt(components[1]), Integer.parseInt(components[2])); } Identifier(int deviceId, int storageId) { this(deviceId, storageId, MtpDocument.DUMMY_HANDLE_FOR_ROOT); } Identifier(int deviceId, int storageId, int objectHandle) { mDeviceId = deviceId; mStorageId = storageId; mObjectHandle = objectHandle; } // TODO: Make the ID persistent. static String createRootId(long deviceId, long storageId) { return String.format("%d:%d", deviceId, storageId); String toRootId() { return String.format("%d:%d", mDeviceId, mStorageId); } // TODO: Make the ID persistent. static String createDocumentId(String rootId, long objectHandle) { return String.format("%s:%d", rootId, objectHandle); String toDocumentId() { return String.format("%d:%d:%d", mDeviceId, mStorageId, mObjectHandle); } } packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocument.java +92 −1 Original line number Diff line number Diff line Loading @@ -16,8 +16,99 @@ package com.android.mtp; 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; // TODO: Implement model class for MTP document. private final int mObjectHandle; private final int mFormat; private final String mName; private final Date mDateModified; private final int mSize; private final int mThumbSize; /** * Constructor for root document. */ MtpDocument(MtpRoot root) { this(DUMMY_HANDLE_FOR_ROOT, 0x3001, // Directory. root.mDescription, null, // Unknown, (int) Math.min(root.mMaxCapacity - root.mFreeSpace, Integer.MAX_VALUE), 0); } MtpDocument(MtpObjectInfo objectInfo) { this(objectInfo.getObjectHandle(), objectInfo.getFormat(), objectInfo.getName(), objectInfo.getDateModified() != 0 ? new Date(objectInfo.getDateModified()) : null, objectInfo.getCompressedSize(), objectInfo.getThumbCompressedSize()); } MtpDocument(int objectHandle, int format, String name, Date dateModified, int size, int thumbSize) { this.mObjectHandle = objectHandle; this.mFormat = format; this.mName = name; this.mDateModified = dateModified; this.mSize = size; this.mThumbSize = thumbSize; } String getMimeType() { // TODO: Add complete list of mime types. switch (mFormat) { case 0x3001: return DocumentsContract.Document.MIME_TYPE_DIR; case 0x3009: return "audio/mp3"; case 0x3801: return "image/jpeg"; default: return ""; } } Object[] getRow(Identifier rootIdentifier, String[] columnNames) { final Object[] rows = new Object[columnNames.length]; for (int i = 0; i < columnNames.length; i++) { if (Document.COLUMN_DOCUMENT_ID.equals(columnNames[i])) { final Identifier identifier = new Identifier( rootIdentifier.mDeviceId, rootIdentifier.mStorageId, mObjectHandle); rows[i] = identifier.toDocumentId(); } else if (Document.COLUMN_DISPLAY_NAME.equals(columnNames[i])) { rows[i] = mName; } else if (Document.COLUMN_MIME_TYPE.equals(columnNames[i])) { rows[i] = getMimeType(); } else if (Document.COLUMN_LAST_MODIFIED.equals(columnNames[i])) { rows[i] = mDateModified != null ? mDateModified.getTime() : null; } else if (Document.COLUMN_FLAGS.equals(columnNames[i])) { int flag = 0; if (mObjectHandle != DUMMY_HANDLE_FOR_ROOT) { flag |= DocumentsContract.Document.FLAG_SUPPORTS_DELETE; if (mThumbSize > 0) { flag |= DocumentsContract.Document.FLAG_SUPPORTS_THUMBNAIL; } } rows[i] = flag; } else if (Document.COLUMN_SIZE.equals(columnNames[i])) { rows[i] = mSize; } else { rows[i] = null; } } return rows; } } packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java +43 −7 Original line number Diff line number Diff line Loading @@ -87,14 +87,14 @@ public class MtpDocumentsProvider extends DocumentsProvider { // TODO: Add retry logic here. for (final MtpRoot root : roots) { final String rootId = Identifier.createRootId(deviceId, root.mStorageId); final Identifier rootIdentifier = new Identifier(deviceId, root.mStorageId); final MatrixCursor.RowBuilder builder = cursor.newRow(); builder.add(Root.COLUMN_ROOT_ID, rootId); builder.add(Root.COLUMN_ROOT_ID, rootIdentifier.toRootId()); builder.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_IS_CHILD); builder.add(Root.COLUMN_TITLE, root.mDescription); builder.add( Root.COLUMN_DOCUMENT_ID, Identifier.createDocumentId(rootId, MtpDocument.DUMMY_HANDLE_FOR_ROOT)); rootIdentifier.toDocumentId()); builder.add(Root.COLUMN_AVAILABLE_BYTES , root.mFreeSpace); } } catch (IOException error) { Loading @@ -109,12 +109,48 @@ public class MtpDocumentsProvider extends DocumentsProvider { @Override public Cursor queryDocument(String documentId, String[] projection) throws FileNotFoundException { if (projection == null) { projection = MtpDocumentsProvider.DEFAULT_DOCUMENT_PROJECTION; } final Identifier identifier = Identifier.createFromDocumentId(documentId); MtpDocument document = null; if (identifier.mObjectHandle != MtpDocument.DUMMY_HANDLE_FOR_ROOT) { try { document = mMtpManager.getDocument(identifier.mDeviceId, identifier.mObjectHandle); } catch (IOException e) { throw new FileNotFoundException(e.getMessage()); } } 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()); } } final MatrixCursor cursor = new MatrixCursor(projection); cursor.addRow(document.getRow( new Identifier(identifier.mDeviceId, identifier.mStorageId), projection)); return cursor; } @Override public Cursor queryChildDocuments(String parentDocumentId, String[] projection, String sortOrder) public Cursor queryChildDocuments( String parentDocumentId, String[] projection, String sortOrder) throws FileNotFoundException { throw new FileNotFoundException(); } Loading packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java +5 −0 Original line number Diff line number Diff line Loading @@ -98,6 +98,11 @@ class MtpManager { return results; } synchronized MtpDocument getDocument(int deviceId, int objectHandle) throws IOException { final MtpDevice device = getDevice(deviceId); return new MtpDocument(device.getObjectInfo(objectHandle)); } private MtpDevice getDevice(int deviceId) throws IOException { final MtpDevice device = mDevices.get(deviceId); if (device == null) { Loading packages/MtpDocumentsProvider/src/com/android/mtp/MtpRoot.java +2 −2 Original line number Diff line number Diff line Loading @@ -21,14 +21,14 @@ import android.mtp.MtpStorageInfo; import com.android.internal.annotations.VisibleForTesting; class MtpRoot { final long mStorageId; final int mStorageId; final String mDescription; final long mFreeSpace; final long mMaxCapacity; final String mVolumeIdentifier; @VisibleForTesting MtpRoot(long storageId, MtpRoot(int storageId, String description, long freeSpace, long maxCapacity, Loading Loading
packages/MtpDocumentsProvider/src/com/android/mtp/Identifier.java +35 −5 Original line number Diff line number Diff line Loading @@ -19,14 +19,44 @@ package com.android.mtp; /** * Static utilities for ID. */ abstract class Identifier { class Identifier { int mDeviceId; int mStorageId; int mObjectHandle; static Identifier createFromRootId(String rootId) { final String[] components = rootId.split(":"); return new Identifier( Integer.parseInt(components[0]), Integer.parseInt(components[1])); } static Identifier createFromDocumentId(String documentId) { final String[] components = documentId.split(":"); return new Identifier( Integer.parseInt(components[0]), Integer.parseInt(components[1]), Integer.parseInt(components[2])); } Identifier(int deviceId, int storageId) { this(deviceId, storageId, MtpDocument.DUMMY_HANDLE_FOR_ROOT); } Identifier(int deviceId, int storageId, int objectHandle) { mDeviceId = deviceId; mStorageId = storageId; mObjectHandle = objectHandle; } // TODO: Make the ID persistent. static String createRootId(long deviceId, long storageId) { return String.format("%d:%d", deviceId, storageId); String toRootId() { return String.format("%d:%d", mDeviceId, mStorageId); } // TODO: Make the ID persistent. static String createDocumentId(String rootId, long objectHandle) { return String.format("%s:%d", rootId, objectHandle); String toDocumentId() { return String.format("%d:%d:%d", mDeviceId, mStorageId, mObjectHandle); } }
packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocument.java +92 −1 Original line number Diff line number Diff line Loading @@ -16,8 +16,99 @@ package com.android.mtp; 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; // TODO: Implement model class for MTP document. private final int mObjectHandle; private final int mFormat; private final String mName; private final Date mDateModified; private final int mSize; private final int mThumbSize; /** * Constructor for root document. */ MtpDocument(MtpRoot root) { this(DUMMY_HANDLE_FOR_ROOT, 0x3001, // Directory. root.mDescription, null, // Unknown, (int) Math.min(root.mMaxCapacity - root.mFreeSpace, Integer.MAX_VALUE), 0); } MtpDocument(MtpObjectInfo objectInfo) { this(objectInfo.getObjectHandle(), objectInfo.getFormat(), objectInfo.getName(), objectInfo.getDateModified() != 0 ? new Date(objectInfo.getDateModified()) : null, objectInfo.getCompressedSize(), objectInfo.getThumbCompressedSize()); } MtpDocument(int objectHandle, int format, String name, Date dateModified, int size, int thumbSize) { this.mObjectHandle = objectHandle; this.mFormat = format; this.mName = name; this.mDateModified = dateModified; this.mSize = size; this.mThumbSize = thumbSize; } String getMimeType() { // TODO: Add complete list of mime types. switch (mFormat) { case 0x3001: return DocumentsContract.Document.MIME_TYPE_DIR; case 0x3009: return "audio/mp3"; case 0x3801: return "image/jpeg"; default: return ""; } } Object[] getRow(Identifier rootIdentifier, String[] columnNames) { final Object[] rows = new Object[columnNames.length]; for (int i = 0; i < columnNames.length; i++) { if (Document.COLUMN_DOCUMENT_ID.equals(columnNames[i])) { final Identifier identifier = new Identifier( rootIdentifier.mDeviceId, rootIdentifier.mStorageId, mObjectHandle); rows[i] = identifier.toDocumentId(); } else if (Document.COLUMN_DISPLAY_NAME.equals(columnNames[i])) { rows[i] = mName; } else if (Document.COLUMN_MIME_TYPE.equals(columnNames[i])) { rows[i] = getMimeType(); } else if (Document.COLUMN_LAST_MODIFIED.equals(columnNames[i])) { rows[i] = mDateModified != null ? mDateModified.getTime() : null; } else if (Document.COLUMN_FLAGS.equals(columnNames[i])) { int flag = 0; if (mObjectHandle != DUMMY_HANDLE_FOR_ROOT) { flag |= DocumentsContract.Document.FLAG_SUPPORTS_DELETE; if (mThumbSize > 0) { flag |= DocumentsContract.Document.FLAG_SUPPORTS_THUMBNAIL; } } rows[i] = flag; } else if (Document.COLUMN_SIZE.equals(columnNames[i])) { rows[i] = mSize; } else { rows[i] = null; } } return rows; } }
packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java +43 −7 Original line number Diff line number Diff line Loading @@ -87,14 +87,14 @@ public class MtpDocumentsProvider extends DocumentsProvider { // TODO: Add retry logic here. for (final MtpRoot root : roots) { final String rootId = Identifier.createRootId(deviceId, root.mStorageId); final Identifier rootIdentifier = new Identifier(deviceId, root.mStorageId); final MatrixCursor.RowBuilder builder = cursor.newRow(); builder.add(Root.COLUMN_ROOT_ID, rootId); builder.add(Root.COLUMN_ROOT_ID, rootIdentifier.toRootId()); builder.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_IS_CHILD); builder.add(Root.COLUMN_TITLE, root.mDescription); builder.add( Root.COLUMN_DOCUMENT_ID, Identifier.createDocumentId(rootId, MtpDocument.DUMMY_HANDLE_FOR_ROOT)); rootIdentifier.toDocumentId()); builder.add(Root.COLUMN_AVAILABLE_BYTES , root.mFreeSpace); } } catch (IOException error) { Loading @@ -109,12 +109,48 @@ public class MtpDocumentsProvider extends DocumentsProvider { @Override public Cursor queryDocument(String documentId, String[] projection) throws FileNotFoundException { if (projection == null) { projection = MtpDocumentsProvider.DEFAULT_DOCUMENT_PROJECTION; } final Identifier identifier = Identifier.createFromDocumentId(documentId); MtpDocument document = null; if (identifier.mObjectHandle != MtpDocument.DUMMY_HANDLE_FOR_ROOT) { try { document = mMtpManager.getDocument(identifier.mDeviceId, identifier.mObjectHandle); } catch (IOException e) { throw new FileNotFoundException(e.getMessage()); } } 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()); } } final MatrixCursor cursor = new MatrixCursor(projection); cursor.addRow(document.getRow( new Identifier(identifier.mDeviceId, identifier.mStorageId), projection)); return cursor; } @Override public Cursor queryChildDocuments(String parentDocumentId, String[] projection, String sortOrder) public Cursor queryChildDocuments( String parentDocumentId, String[] projection, String sortOrder) throws FileNotFoundException { throw new FileNotFoundException(); } Loading
packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java +5 −0 Original line number Diff line number Diff line Loading @@ -98,6 +98,11 @@ class MtpManager { return results; } synchronized MtpDocument getDocument(int deviceId, int objectHandle) throws IOException { final MtpDevice device = getDevice(deviceId); return new MtpDocument(device.getObjectInfo(objectHandle)); } private MtpDevice getDevice(int deviceId) throws IOException { final MtpDevice device = mDevices.get(deviceId); if (device == null) { Loading
packages/MtpDocumentsProvider/src/com/android/mtp/MtpRoot.java +2 −2 Original line number Diff line number Diff line Loading @@ -21,14 +21,14 @@ import android.mtp.MtpStorageInfo; import com.android.internal.annotations.VisibleForTesting; class MtpRoot { final long mStorageId; final int mStorageId; final String mDescription; final long mFreeSpace; final long mMaxCapacity; final String mVolumeIdentifier; @VisibleForTesting MtpRoot(long storageId, MtpRoot(int storageId, String description, long freeSpace, long maxCapacity, Loading