Loading packages/MtpDocumentsProvider/src/com/android/mtp/AppFuse.java +2 −0 Original line number Original line Diff line number Diff line Loading @@ -133,6 +133,8 @@ public class AppFuse { return mCallback.readObjectBytes(inode, offset, size, mBuffer); return mCallback.readObjectBytes(inode, offset, size, mBuffer); } catch (IOException e) { } catch (IOException e) { return -OsConstants.EIO; return -OsConstants.EIO; } catch (UnsupportedOperationException e) { return -OsConstants.ENOTSUP; } } } } Loading packages/MtpDocumentsProvider/src/com/android/mtp/Mapper.java +7 −2 Original line number Original line Diff line number Diff line Loading @@ -89,7 +89,8 @@ class Mapper { * @return If roots are added or removed from the database. * @return If roots are added or removed from the database. * @throws FileNotFoundException * @throws FileNotFoundException */ */ synchronized boolean putStorageDocuments(String parentDocumentId, MtpRoot[] roots) synchronized boolean putStorageDocuments( String parentDocumentId, int[] operationsSupported, MtpRoot[] roots) throws FileNotFoundException { throws FileNotFoundException { final SQLiteDatabase database = mDatabase.getSQLiteDatabase(); final SQLiteDatabase database = mDatabase.getSQLiteDatabase(); database.beginTransaction(); database.beginTransaction(); Loading @@ -100,7 +101,11 @@ class Mapper { valuesList[i] = new ContentValues(); valuesList[i] = new ContentValues(); extraValuesList[i] = new ContentValues(); extraValuesList[i] = new ContentValues(); MtpDatabase.getStorageDocumentValues( MtpDatabase.getStorageDocumentValues( valuesList[i], extraValuesList[i], parentDocumentId, roots[i]); valuesList[i], extraValuesList[i], parentDocumentId, operationsSupported, roots[i]); } } final boolean changed = putDocuments( final boolean changed = putDocuments( parentDocumentId, parentDocumentId, Loading packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java +14 −6 Original line number Original line Diff line number Diff line Loading @@ -689,9 +689,7 @@ class MtpDatabase { values.putNull(Document.COLUMN_SIZE); values.putNull(Document.COLUMN_SIZE); extraValues.clear(); extraValues.clear(); extraValues.put( extraValues.put(Root.COLUMN_FLAGS, getRootFlags(device.operationsSupported)); Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE); extraValues.putNull(Root.COLUMN_AVAILABLE_BYTES); extraValues.putNull(Root.COLUMN_AVAILABLE_BYTES); extraValues.putNull(Root.COLUMN_CAPACITY_BYTES); extraValues.putNull(Root.COLUMN_CAPACITY_BYTES); extraValues.put(Root.COLUMN_MIME_TYPES, ""); extraValues.put(Root.COLUMN_MIME_TYPES, ""); Loading @@ -700,12 +698,16 @@ class MtpDatabase { /** /** * Gets {@link ContentValues} for the given root. * Gets {@link ContentValues} for the given root. * @param values {@link ContentValues} that receives values. * @param values {@link ContentValues} that receives values. * @param extraValues {@link ContentValues} that receives extra values for roots. * @param parentDocumentId Parent document ID. * @param supportedOperations Array of Operation code supported by the device. * @param root Root to be converted {@link ContentValues}. * @param root Root to be converted {@link ContentValues}. */ */ static void getStorageDocumentValues( static void getStorageDocumentValues( ContentValues values, ContentValues values, ContentValues extraValues, ContentValues extraValues, String parentDocumentId, String parentDocumentId, int[] operationsSupported, MtpRoot root) { MtpRoot root) { values.clear(); values.clear(); values.put(COLUMN_DEVICE_ID, root.mDeviceId); values.put(COLUMN_DEVICE_ID, root.mDeviceId); Loading @@ -722,9 +724,7 @@ class MtpDatabase { values.put(Document.COLUMN_FLAGS, 0); values.put(Document.COLUMN_FLAGS, 0); values.put(Document.COLUMN_SIZE, root.mMaxCapacity - root.mFreeSpace); values.put(Document.COLUMN_SIZE, root.mMaxCapacity - root.mFreeSpace); extraValues.put( extraValues.put(Root.COLUMN_FLAGS, getRootFlags(operationsSupported)); Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE); extraValues.put(Root.COLUMN_AVAILABLE_BYTES, root.mFreeSpace); extraValues.put(Root.COLUMN_AVAILABLE_BYTES, root.mFreeSpace); extraValues.put(Root.COLUMN_CAPACITY_BYTES, root.mMaxCapacity); extraValues.put(Root.COLUMN_CAPACITY_BYTES, root.mMaxCapacity); extraValues.put(Root.COLUMN_MIME_TYPES, ""); extraValues.put(Root.COLUMN_MIME_TYPES, ""); Loading Loading @@ -785,6 +785,14 @@ class MtpDatabase { return "application/octet-stream"; return "application/octet-stream"; } } private static int getRootFlags(int[] operationsSupported) { int rootFlag = Root.FLAG_SUPPORTS_IS_CHILD; if (MtpDeviceRecord.isWritingSupported(operationsSupported)) { rootFlag |= Root.FLAG_SUPPORTS_CREATE; } return rootFlag; } static String[] strings(Object... args) { static String[] strings(Object... args) { final String[] results = new String[args.length]; final String[] results = new String[args.length]; for (int i = 0; i < args.length; i++) { for (int i = 0; i < args.length; i++) { Loading packages/MtpDocumentsProvider/src/com/android/mtp/MtpDeviceRecord.java +26 −0 Original line number Original line Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.mtp; package com.android.mtp; import android.annotation.Nullable; import android.annotation.Nullable; import android.mtp.MtpConstants; class MtpDeviceRecord { class MtpDeviceRecord { public final int deviceId; public final int deviceId; Loading @@ -38,4 +39,29 @@ class MtpDeviceRecord { this.operationsSupported = operationsSupported; this.operationsSupported = operationsSupported; this.eventsSupported = eventsSupported; this.eventsSupported = eventsSupported; } } /** * Helper method to check operations/events are supported by the device or not. */ static boolean isSupported(@Nullable int[] supportedList, int code) { if (supportedList == null) { return false; } for (int i = 0; i < supportedList.length; i++) { if (supportedList[i] == code) { return true; } } return false; } static boolean isPartialReadSupported(@Nullable int[] supportedList, long fileSize) { return fileSize <= 0xffffffffl && isSupported(supportedList, MtpConstants.OPERATION_GET_PARTIAL_OBJECT); } static boolean isWritingSupported(@Nullable int[] supportedList) { return isSupported(supportedList, MtpConstants.OPERATION_SEND_OBJECT_INFO) && isSupported(supportedList, MtpConstants.OPERATION_SEND_OBJECT); } } } packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java +39 −22 Original line number Original line Diff line number Diff line Loading @@ -201,6 +201,7 @@ public class MtpDocumentsProvider extends DocumentsProvider { final Identifier identifier = mDatabase.createIdentifier(documentId); final Identifier identifier = mDatabase.createIdentifier(documentId); try { try { openDevice(identifier.mDeviceId); openDevice(identifier.mDeviceId); final MtpDeviceRecord device = getDeviceToolkit(identifier.mDeviceId).mDeviceRecord; switch (mode) { switch (mode) { case "r": case "r": final long fileSize = getFileSize(documentId); final long fileSize = getFileSize(documentId); Loading @@ -208,7 +209,8 @@ public class MtpDocumentsProvider extends DocumentsProvider { // 4GB. Fallback to non-seekable file descriptor. // 4GB. Fallback to non-seekable file descriptor. // TODO: Use getPartialObject64 for MTP devices that support Android vendor // TODO: Use getPartialObject64 for MTP devices that support Android vendor // extension. // extension. if (fileSize <= 0xffffffffl) { if (MtpDeviceRecord.isPartialReadSupported( device.operationsSupported, fileSize)) { return mAppFuse.openFile(Integer.parseInt(documentId)); return mAppFuse.openFile(Integer.parseInt(documentId)); } else { } else { return getPipeManager(identifier).readDocument(mMtpManager, identifier); return getPipeManager(identifier).readDocument(mMtpManager, identifier); Loading @@ -216,8 +218,13 @@ public class MtpDocumentsProvider extends DocumentsProvider { case "w": case "w": // TODO: Clear the parent document loader task (if exists) and call notify // TODO: Clear the parent document loader task (if exists) and call notify // when writing is completed. // when writing is completed. if (MtpDeviceRecord.isWritingSupported(device.operationsSupported)) { return getPipeManager(identifier).writeDocument( return getPipeManager(identifier).writeDocument( getContext(), mMtpManager, identifier); getContext(), mMtpManager, identifier); } else { throw new UnsupportedOperationException( "The device does not support writing operation."); } case "rw": case "rw": // TODO: Add support for "rw" mode. // TODO: Add support for "rw" mode. throw new UnsupportedOperationException( throw new UnsupportedOperationException( Loading Loading @@ -290,6 +297,10 @@ public class MtpDocumentsProvider extends DocumentsProvider { try { try { final Identifier parentId = mDatabase.createIdentifier(parentDocumentId); final Identifier parentId = mDatabase.createIdentifier(parentDocumentId); openDevice(parentId.mDeviceId); openDevice(parentId.mDeviceId); final MtpDeviceRecord record = getDeviceToolkit(parentId.mDeviceId).mDeviceRecord; if (!MtpDeviceRecord.isWritingSupported(record.operationsSupported)) { throw new UnsupportedOperationException(); } final ParcelFileDescriptor pipe[] = ParcelFileDescriptor.createReliablePipe(); final ParcelFileDescriptor pipe[] = ParcelFileDescriptor.createReliablePipe(); pipe[0].close(); // 0 bytes for a new document. pipe[0].close(); // 0 bytes for a new document. final int formatCode = Document.MIME_TYPE_DIR.equals(mimeType) ? final int formatCode = Document.MIME_TYPE_DIR.equals(mimeType) ? Loading Loading @@ -323,9 +334,9 @@ public class MtpDocumentsProvider extends DocumentsProvider { if (DEBUG) { if (DEBUG) { Log.d(TAG, "Open device " + deviceId); Log.d(TAG, "Open device " + deviceId); } } mMtpManager.openDevice(deviceId); final MtpDeviceRecord device = mMtpManager.openDevice(deviceId); final DeviceToolkit toolkit = final DeviceToolkit toolkit = new DeviceToolkit(deviceId, mMtpManager, mResolver, mDatabase); new DeviceToolkit(deviceId, mMtpManager, mResolver, mDatabase, device); mDeviceToolkits.put(deviceId, toolkit); mDeviceToolkits.put(deviceId, toolkit); mIntentSender.sendUpdateNotificationIntent(); mIntentSender.sendUpdateNotificationIntent(); try { try { Loading @@ -347,20 +358,15 @@ public class MtpDocumentsProvider extends DocumentsProvider { mIntentSender.sendUpdateNotificationIntent(); mIntentSender.sendUpdateNotificationIntent(); } } int[] getOpenedDeviceIds() { MtpDeviceRecord[] getOpenedDeviceRecordsCache() { synchronized (mDeviceListLock) { return mMtpManager.getOpenedDeviceIds(); } } String getDeviceName(int deviceId) throws IOException { synchronized (mDeviceListLock) { synchronized (mDeviceListLock) { for (final MtpDeviceRecord device : mMtpManager.getDevices()) { final MtpDeviceRecord[] records = new MtpDeviceRecord[mDeviceToolkits.size()]; if (device.deviceId == deviceId) { int i = 0; return device.name; for (final DeviceToolkit toolkit : mDeviceToolkits.values()) { } records[i] = toolkit.mDeviceRecord; i++; } } throw new IOException("Not found the device: " + Integer.toString(deviceId)); return records; } } } } Loading Loading @@ -391,7 +397,10 @@ public class MtpDocumentsProvider extends DocumentsProvider { public void shutdown() { public void shutdown() { synchronized (mDeviceListLock) { synchronized (mDeviceListLock) { try { try { for (final int id : mMtpManager.getOpenedDeviceIds()) { // Copy the opened key set because it will be modified when closing devices. final Integer[] keySet = mDeviceToolkits.keySet().toArray(new Integer[mDeviceToolkits.size()]); for (final int id : keySet) { closeDeviceInternal(id); closeDeviceInternal(id); } } } catch (InterruptedException|IOException e) { } catch (InterruptedException|IOException e) { Loading Loading @@ -432,7 +441,7 @@ public class MtpDocumentsProvider extends DocumentsProvider { getDeviceToolkit(deviceId).mDocumentLoader.close(); getDeviceToolkit(deviceId).mDocumentLoader.close(); mDeviceToolkits.remove(deviceId); mDeviceToolkits.remove(deviceId); mMtpManager.closeDevice(deviceId); mMtpManager.closeDevice(deviceId); if (getOpenedDeviceIds().length == 0) { if (mDeviceToolkits.size() == 0) { mRootScanner.pause(); mRootScanner.pause(); } } } } Loading Loading @@ -488,11 +497,14 @@ public class MtpDocumentsProvider extends DocumentsProvider { private static class DeviceToolkit { private static class DeviceToolkit { public final PipeManager mPipeManager; public final PipeManager mPipeManager; public final DocumentLoader mDocumentLoader; public final DocumentLoader mDocumentLoader; public final MtpDeviceRecord mDeviceRecord; public DeviceToolkit( public DeviceToolkit( int deviceId, MtpManager manager, ContentResolver resolver, MtpDatabase database) { int deviceId, MtpManager manager, ContentResolver resolver, MtpDatabase database, MtpDeviceRecord record) { mPipeManager = new PipeManager(database); mPipeManager = new PipeManager(database); mDocumentLoader = new DocumentLoader(deviceId, manager, resolver, database); mDocumentLoader = new DocumentLoader(deviceId, manager, resolver, database); mDeviceRecord = record; } } } } Loading @@ -501,8 +513,13 @@ public class MtpDocumentsProvider extends DocumentsProvider { public long readObjectBytes( public long readObjectBytes( int inode, long offset, long size, byte[] buffer) throws IOException { int inode, long offset, long size, byte[] buffer) throws IOException { final Identifier identifier = mDatabase.createIdentifier(Integer.toString(inode)); final Identifier identifier = mDatabase.createIdentifier(Integer.toString(inode)); final MtpDeviceRecord record = getDeviceToolkit(identifier.mDeviceId).mDeviceRecord; if (MtpDeviceRecord.isPartialReadSupported(record.operationsSupported, offset)) { return mMtpManager.getPartialObject( return mMtpManager.getPartialObject( identifier.mDeviceId, identifier.mObjectHandle, offset, size, buffer); identifier.mDeviceId, identifier.mObjectHandle, offset, size, buffer); } else { throw new UnsupportedOperationException(); } } } @Override @Override Loading Loading
packages/MtpDocumentsProvider/src/com/android/mtp/AppFuse.java +2 −0 Original line number Original line Diff line number Diff line Loading @@ -133,6 +133,8 @@ public class AppFuse { return mCallback.readObjectBytes(inode, offset, size, mBuffer); return mCallback.readObjectBytes(inode, offset, size, mBuffer); } catch (IOException e) { } catch (IOException e) { return -OsConstants.EIO; return -OsConstants.EIO; } catch (UnsupportedOperationException e) { return -OsConstants.ENOTSUP; } } } } Loading
packages/MtpDocumentsProvider/src/com/android/mtp/Mapper.java +7 −2 Original line number Original line Diff line number Diff line Loading @@ -89,7 +89,8 @@ class Mapper { * @return If roots are added or removed from the database. * @return If roots are added or removed from the database. * @throws FileNotFoundException * @throws FileNotFoundException */ */ synchronized boolean putStorageDocuments(String parentDocumentId, MtpRoot[] roots) synchronized boolean putStorageDocuments( String parentDocumentId, int[] operationsSupported, MtpRoot[] roots) throws FileNotFoundException { throws FileNotFoundException { final SQLiteDatabase database = mDatabase.getSQLiteDatabase(); final SQLiteDatabase database = mDatabase.getSQLiteDatabase(); database.beginTransaction(); database.beginTransaction(); Loading @@ -100,7 +101,11 @@ class Mapper { valuesList[i] = new ContentValues(); valuesList[i] = new ContentValues(); extraValuesList[i] = new ContentValues(); extraValuesList[i] = new ContentValues(); MtpDatabase.getStorageDocumentValues( MtpDatabase.getStorageDocumentValues( valuesList[i], extraValuesList[i], parentDocumentId, roots[i]); valuesList[i], extraValuesList[i], parentDocumentId, operationsSupported, roots[i]); } } final boolean changed = putDocuments( final boolean changed = putDocuments( parentDocumentId, parentDocumentId, Loading
packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java +14 −6 Original line number Original line Diff line number Diff line Loading @@ -689,9 +689,7 @@ class MtpDatabase { values.putNull(Document.COLUMN_SIZE); values.putNull(Document.COLUMN_SIZE); extraValues.clear(); extraValues.clear(); extraValues.put( extraValues.put(Root.COLUMN_FLAGS, getRootFlags(device.operationsSupported)); Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE); extraValues.putNull(Root.COLUMN_AVAILABLE_BYTES); extraValues.putNull(Root.COLUMN_AVAILABLE_BYTES); extraValues.putNull(Root.COLUMN_CAPACITY_BYTES); extraValues.putNull(Root.COLUMN_CAPACITY_BYTES); extraValues.put(Root.COLUMN_MIME_TYPES, ""); extraValues.put(Root.COLUMN_MIME_TYPES, ""); Loading @@ -700,12 +698,16 @@ class MtpDatabase { /** /** * Gets {@link ContentValues} for the given root. * Gets {@link ContentValues} for the given root. * @param values {@link ContentValues} that receives values. * @param values {@link ContentValues} that receives values. * @param extraValues {@link ContentValues} that receives extra values for roots. * @param parentDocumentId Parent document ID. * @param supportedOperations Array of Operation code supported by the device. * @param root Root to be converted {@link ContentValues}. * @param root Root to be converted {@link ContentValues}. */ */ static void getStorageDocumentValues( static void getStorageDocumentValues( ContentValues values, ContentValues values, ContentValues extraValues, ContentValues extraValues, String parentDocumentId, String parentDocumentId, int[] operationsSupported, MtpRoot root) { MtpRoot root) { values.clear(); values.clear(); values.put(COLUMN_DEVICE_ID, root.mDeviceId); values.put(COLUMN_DEVICE_ID, root.mDeviceId); Loading @@ -722,9 +724,7 @@ class MtpDatabase { values.put(Document.COLUMN_FLAGS, 0); values.put(Document.COLUMN_FLAGS, 0); values.put(Document.COLUMN_SIZE, root.mMaxCapacity - root.mFreeSpace); values.put(Document.COLUMN_SIZE, root.mMaxCapacity - root.mFreeSpace); extraValues.put( extraValues.put(Root.COLUMN_FLAGS, getRootFlags(operationsSupported)); Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE); extraValues.put(Root.COLUMN_AVAILABLE_BYTES, root.mFreeSpace); extraValues.put(Root.COLUMN_AVAILABLE_BYTES, root.mFreeSpace); extraValues.put(Root.COLUMN_CAPACITY_BYTES, root.mMaxCapacity); extraValues.put(Root.COLUMN_CAPACITY_BYTES, root.mMaxCapacity); extraValues.put(Root.COLUMN_MIME_TYPES, ""); extraValues.put(Root.COLUMN_MIME_TYPES, ""); Loading Loading @@ -785,6 +785,14 @@ class MtpDatabase { return "application/octet-stream"; return "application/octet-stream"; } } private static int getRootFlags(int[] operationsSupported) { int rootFlag = Root.FLAG_SUPPORTS_IS_CHILD; if (MtpDeviceRecord.isWritingSupported(operationsSupported)) { rootFlag |= Root.FLAG_SUPPORTS_CREATE; } return rootFlag; } static String[] strings(Object... args) { static String[] strings(Object... args) { final String[] results = new String[args.length]; final String[] results = new String[args.length]; for (int i = 0; i < args.length; i++) { for (int i = 0; i < args.length; i++) { Loading
packages/MtpDocumentsProvider/src/com/android/mtp/MtpDeviceRecord.java +26 −0 Original line number Original line Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.mtp; package com.android.mtp; import android.annotation.Nullable; import android.annotation.Nullable; import android.mtp.MtpConstants; class MtpDeviceRecord { class MtpDeviceRecord { public final int deviceId; public final int deviceId; Loading @@ -38,4 +39,29 @@ class MtpDeviceRecord { this.operationsSupported = operationsSupported; this.operationsSupported = operationsSupported; this.eventsSupported = eventsSupported; this.eventsSupported = eventsSupported; } } /** * Helper method to check operations/events are supported by the device or not. */ static boolean isSupported(@Nullable int[] supportedList, int code) { if (supportedList == null) { return false; } for (int i = 0; i < supportedList.length; i++) { if (supportedList[i] == code) { return true; } } return false; } static boolean isPartialReadSupported(@Nullable int[] supportedList, long fileSize) { return fileSize <= 0xffffffffl && isSupported(supportedList, MtpConstants.OPERATION_GET_PARTIAL_OBJECT); } static boolean isWritingSupported(@Nullable int[] supportedList) { return isSupported(supportedList, MtpConstants.OPERATION_SEND_OBJECT_INFO) && isSupported(supportedList, MtpConstants.OPERATION_SEND_OBJECT); } } }
packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java +39 −22 Original line number Original line Diff line number Diff line Loading @@ -201,6 +201,7 @@ public class MtpDocumentsProvider extends DocumentsProvider { final Identifier identifier = mDatabase.createIdentifier(documentId); final Identifier identifier = mDatabase.createIdentifier(documentId); try { try { openDevice(identifier.mDeviceId); openDevice(identifier.mDeviceId); final MtpDeviceRecord device = getDeviceToolkit(identifier.mDeviceId).mDeviceRecord; switch (mode) { switch (mode) { case "r": case "r": final long fileSize = getFileSize(documentId); final long fileSize = getFileSize(documentId); Loading @@ -208,7 +209,8 @@ public class MtpDocumentsProvider extends DocumentsProvider { // 4GB. Fallback to non-seekable file descriptor. // 4GB. Fallback to non-seekable file descriptor. // TODO: Use getPartialObject64 for MTP devices that support Android vendor // TODO: Use getPartialObject64 for MTP devices that support Android vendor // extension. // extension. if (fileSize <= 0xffffffffl) { if (MtpDeviceRecord.isPartialReadSupported( device.operationsSupported, fileSize)) { return mAppFuse.openFile(Integer.parseInt(documentId)); return mAppFuse.openFile(Integer.parseInt(documentId)); } else { } else { return getPipeManager(identifier).readDocument(mMtpManager, identifier); return getPipeManager(identifier).readDocument(mMtpManager, identifier); Loading @@ -216,8 +218,13 @@ public class MtpDocumentsProvider extends DocumentsProvider { case "w": case "w": // TODO: Clear the parent document loader task (if exists) and call notify // TODO: Clear the parent document loader task (if exists) and call notify // when writing is completed. // when writing is completed. if (MtpDeviceRecord.isWritingSupported(device.operationsSupported)) { return getPipeManager(identifier).writeDocument( return getPipeManager(identifier).writeDocument( getContext(), mMtpManager, identifier); getContext(), mMtpManager, identifier); } else { throw new UnsupportedOperationException( "The device does not support writing operation."); } case "rw": case "rw": // TODO: Add support for "rw" mode. // TODO: Add support for "rw" mode. throw new UnsupportedOperationException( throw new UnsupportedOperationException( Loading Loading @@ -290,6 +297,10 @@ public class MtpDocumentsProvider extends DocumentsProvider { try { try { final Identifier parentId = mDatabase.createIdentifier(parentDocumentId); final Identifier parentId = mDatabase.createIdentifier(parentDocumentId); openDevice(parentId.mDeviceId); openDevice(parentId.mDeviceId); final MtpDeviceRecord record = getDeviceToolkit(parentId.mDeviceId).mDeviceRecord; if (!MtpDeviceRecord.isWritingSupported(record.operationsSupported)) { throw new UnsupportedOperationException(); } final ParcelFileDescriptor pipe[] = ParcelFileDescriptor.createReliablePipe(); final ParcelFileDescriptor pipe[] = ParcelFileDescriptor.createReliablePipe(); pipe[0].close(); // 0 bytes for a new document. pipe[0].close(); // 0 bytes for a new document. final int formatCode = Document.MIME_TYPE_DIR.equals(mimeType) ? final int formatCode = Document.MIME_TYPE_DIR.equals(mimeType) ? Loading Loading @@ -323,9 +334,9 @@ public class MtpDocumentsProvider extends DocumentsProvider { if (DEBUG) { if (DEBUG) { Log.d(TAG, "Open device " + deviceId); Log.d(TAG, "Open device " + deviceId); } } mMtpManager.openDevice(deviceId); final MtpDeviceRecord device = mMtpManager.openDevice(deviceId); final DeviceToolkit toolkit = final DeviceToolkit toolkit = new DeviceToolkit(deviceId, mMtpManager, mResolver, mDatabase); new DeviceToolkit(deviceId, mMtpManager, mResolver, mDatabase, device); mDeviceToolkits.put(deviceId, toolkit); mDeviceToolkits.put(deviceId, toolkit); mIntentSender.sendUpdateNotificationIntent(); mIntentSender.sendUpdateNotificationIntent(); try { try { Loading @@ -347,20 +358,15 @@ public class MtpDocumentsProvider extends DocumentsProvider { mIntentSender.sendUpdateNotificationIntent(); mIntentSender.sendUpdateNotificationIntent(); } } int[] getOpenedDeviceIds() { MtpDeviceRecord[] getOpenedDeviceRecordsCache() { synchronized (mDeviceListLock) { return mMtpManager.getOpenedDeviceIds(); } } String getDeviceName(int deviceId) throws IOException { synchronized (mDeviceListLock) { synchronized (mDeviceListLock) { for (final MtpDeviceRecord device : mMtpManager.getDevices()) { final MtpDeviceRecord[] records = new MtpDeviceRecord[mDeviceToolkits.size()]; if (device.deviceId == deviceId) { int i = 0; return device.name; for (final DeviceToolkit toolkit : mDeviceToolkits.values()) { } records[i] = toolkit.mDeviceRecord; i++; } } throw new IOException("Not found the device: " + Integer.toString(deviceId)); return records; } } } } Loading Loading @@ -391,7 +397,10 @@ public class MtpDocumentsProvider extends DocumentsProvider { public void shutdown() { public void shutdown() { synchronized (mDeviceListLock) { synchronized (mDeviceListLock) { try { try { for (final int id : mMtpManager.getOpenedDeviceIds()) { // Copy the opened key set because it will be modified when closing devices. final Integer[] keySet = mDeviceToolkits.keySet().toArray(new Integer[mDeviceToolkits.size()]); for (final int id : keySet) { closeDeviceInternal(id); closeDeviceInternal(id); } } } catch (InterruptedException|IOException e) { } catch (InterruptedException|IOException e) { Loading Loading @@ -432,7 +441,7 @@ public class MtpDocumentsProvider extends DocumentsProvider { getDeviceToolkit(deviceId).mDocumentLoader.close(); getDeviceToolkit(deviceId).mDocumentLoader.close(); mDeviceToolkits.remove(deviceId); mDeviceToolkits.remove(deviceId); mMtpManager.closeDevice(deviceId); mMtpManager.closeDevice(deviceId); if (getOpenedDeviceIds().length == 0) { if (mDeviceToolkits.size() == 0) { mRootScanner.pause(); mRootScanner.pause(); } } } } Loading Loading @@ -488,11 +497,14 @@ public class MtpDocumentsProvider extends DocumentsProvider { private static class DeviceToolkit { private static class DeviceToolkit { public final PipeManager mPipeManager; public final PipeManager mPipeManager; public final DocumentLoader mDocumentLoader; public final DocumentLoader mDocumentLoader; public final MtpDeviceRecord mDeviceRecord; public DeviceToolkit( public DeviceToolkit( int deviceId, MtpManager manager, ContentResolver resolver, MtpDatabase database) { int deviceId, MtpManager manager, ContentResolver resolver, MtpDatabase database, MtpDeviceRecord record) { mPipeManager = new PipeManager(database); mPipeManager = new PipeManager(database); mDocumentLoader = new DocumentLoader(deviceId, manager, resolver, database); mDocumentLoader = new DocumentLoader(deviceId, manager, resolver, database); mDeviceRecord = record; } } } } Loading @@ -501,8 +513,13 @@ public class MtpDocumentsProvider extends DocumentsProvider { public long readObjectBytes( public long readObjectBytes( int inode, long offset, long size, byte[] buffer) throws IOException { int inode, long offset, long size, byte[] buffer) throws IOException { final Identifier identifier = mDatabase.createIdentifier(Integer.toString(inode)); final Identifier identifier = mDatabase.createIdentifier(Integer.toString(inode)); final MtpDeviceRecord record = getDeviceToolkit(identifier.mDeviceId).mDeviceRecord; if (MtpDeviceRecord.isPartialReadSupported(record.operationsSupported, offset)) { return mMtpManager.getPartialObject( return mMtpManager.getPartialObject( identifier.mDeviceId, identifier.mObjectHandle, offset, size, buffer); identifier.mDeviceId, identifier.mObjectHandle, offset, size, buffer); } else { throw new UnsupportedOperationException(); } } } @Override @Override Loading