Loading packages/MtpDocumentsProvider/src/com/android/mtp/Mapper.java +13 −34 Original line number Diff line number Diff line Loading @@ -42,7 +42,6 @@ import static com.android.mtp.MtpDatabase.strings; * Also see the comments of {@link MtpDatabase}. */ class Mapper { private static final String[] EMPTY_ARGS = new String[0]; private final MtpDatabase mDatabase; /** Loading @@ -56,43 +55,21 @@ class Mapper { mDatabase = database; } synchronized String putDeviceDocument(int deviceId, String name, MtpRoot[] roots) { final SQLiteDatabase database = mDatabase.getSQLiteDatabase(); Preconditions.checkState(mMappingMode.containsKey(/* no parent for root */ null)); database.beginTransaction(); try { final ContentValues[] valuesList = new ContentValues[1]; valuesList[0] = new ContentValues(); MtpDatabase.getDeviceDocumentValues(valuesList[0], deviceId, name, roots); putDocuments( valuesList, COLUMN_PARENT_DOCUMENT_ID + " IS NULL", EMPTY_ARGS, /* heuristic */ false, COLUMN_DEVICE_ID); database.setTransactionSuccessful(); return valuesList[0].getAsString(Document.COLUMN_DOCUMENT_ID); } finally { database.endTransaction(); } } /** * Puts root information to database. * @param parentDocumentId Document ID of device document. * @param deviceId Device ID * @param resources Resources required to localize root name. * @param roots List of root information. * @return If roots are added or removed from the database. */ synchronized boolean putRootDocuments( String parentDocumentId, Resources resources, MtpRoot[] roots) { synchronized boolean putRootDocuments(int deviceId, Resources resources, MtpRoot[] roots) { final SQLiteDatabase database = mDatabase.getSQLiteDatabase(); database.beginTransaction(); try { final boolean heuristic; final String mapColumn; Preconditions.checkState(mMappingMode.containsKey(parentDocumentId)); switch (mMappingMode.get(parentDocumentId)) { Preconditions.checkState(mMappingMode.containsKey(/* no parent for root */ null)); switch (mMappingMode.get(/* no parent for root */ null)) { case MAP_BY_MTP_IDENTIFIER: heuristic = false; mapColumn = COLUMN_STORAGE_ID; Loading @@ -106,14 +83,16 @@ class Mapper { } final ContentValues[] valuesList = new ContentValues[roots.length]; for (int i = 0; i < roots.length; i++) { if (roots[i].mDeviceId != deviceId) { throw new IllegalArgumentException(); } valuesList[i] = new ContentValues(); MtpDatabase.getStorageDocumentValues( valuesList[i], resources, parentDocumentId, roots[i]); MtpDatabase.getRootDocumentValues(valuesList[i], resources, roots[i]); } final boolean changed = putDocuments( valuesList, COLUMN_PARENT_DOCUMENT_ID + "=?", strings(parentDocumentId), COLUMN_PARENT_DOCUMENT_ID + " IS NULL", new String[0], heuristic, mapColumn); final ContentValues values = new ContentValues(); Loading Loading @@ -167,7 +146,7 @@ class Mapper { final ContentValues[] valuesList = new ContentValues[documents.length]; for (int i = 0; i < documents.length; i++) { valuesList[i] = new ContentValues(); MtpDatabase.getObjectDocumentValues( MtpDatabase.getChildDocumentValues( valuesList[i], deviceId, parentId, documents[i]); } putDocuments( Loading Loading @@ -214,7 +193,7 @@ class Mapper { args = strings(parentDocumentId); } else { selection = COLUMN_PARENT_DOCUMENT_ID + " IS NULL"; args = EMPTY_ARGS; args = new String[0]; } final SQLiteDatabase database = mDatabase.getSQLiteDatabase(); Loading Loading @@ -333,7 +312,7 @@ class Mapper { args = strings(parentId); } else { selection = COLUMN_PARENT_DOCUMENT_ID + " IS NULL"; args = EMPTY_ARGS; args = new String[0]; } final String groupKey; switch (mMappingMode.get(parentId)) { Loading packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java +13 −39 Original line number Diff line number Diff line Loading @@ -22,7 +22,6 @@ import android.content.ContentValues; import android.content.Context; import android.content.res.Resources; import android.database.Cursor; import android.database.MatrixCursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteQueryBuilder; Loading @@ -36,9 +35,9 @@ import android.provider.DocumentsContract.Root; import com.android.internal.annotations.VisibleForTesting; import java.io.FileNotFoundException; import java.util.HashMap; import java.util.Map; import java.util.HashSet; import java.util.Objects; import java.util.Set; /** * Database for MTP objects. Loading Loading @@ -108,14 +107,11 @@ class MtpDatabase { * @return Database cursor. */ Cursor queryRoots(String[] columnNames) { final SQLiteQueryBuilder builder = new SQLiteQueryBuilder(); builder.setTables(JOIN_ROOTS); builder.setProjectionMap(COLUMN_MAP_ROOTS); return builder.query( mDatabase, return mDatabase.query( VIEW_ROOTS, columnNames, COLUMN_ROW_STATE + " IN (?, ?) AND " + COLUMN_DOCUMENT_TYPE + " = ?", strings(ROW_STATE_VALID, ROW_STATE_INVALIDATED, DOCUMENT_TYPE_STORAGE), COLUMN_ROW_STATE + " IN (?, ?)", strings(ROW_STATE_VALID, ROW_STATE_INVALIDATED), null, null, null); Loading @@ -132,8 +128,8 @@ class MtpDatabase { return mDatabase.query( TABLE_DOCUMENTS, columnNames, COLUMN_ROW_STATE + " IN (?, ?) AND " + COLUMN_DOCUMENT_TYPE + "=?", strings(ROW_STATE_VALID, ROW_STATE_INVALIDATED, DOCUMENT_TYPE_STORAGE), COLUMN_ROW_STATE + " IN (?, ?)", strings(ROW_STATE_VALID, ROW_STATE_INVALIDATED), null, null, null); Loading Loading @@ -220,7 +216,7 @@ class MtpDatabase { */ String putNewDocument(int deviceId, String parentDocumentId, MtpObjectInfo info) { final ContentValues values = new ContentValues(); getObjectDocumentValues(values, deviceId, parentDocumentId, info); getChildDocumentValues(values, deviceId, parentDocumentId, info); mDatabase.beginTransaction(); try { final long id = mDatabase.insert(TABLE_DOCUMENTS, null, values); Loading Loading @@ -348,6 +344,7 @@ class MtpDatabase { public void onCreate(SQLiteDatabase db) { db.execSQL(QUERY_CREATE_DOCUMENTS); db.execSQL(QUERY_CREATE_ROOT_EXTRA); db.execSQL(QUERY_CREATE_VIEW_ROOTS); } @Override Loading @@ -361,41 +358,18 @@ class MtpDatabase { context.deleteDatabase(DATABASE_NAME); } static void getDeviceDocumentValues( ContentValues values, int deviceId, String name, MtpRoot[] roots) { values.clear(); values.put(COLUMN_DEVICE_ID, deviceId); values.putNull(COLUMN_STORAGE_ID); values.putNull(COLUMN_OBJECT_HANDLE); values.putNull(COLUMN_PARENT_DOCUMENT_ID); values.put(COLUMN_ROW_STATE, ROW_STATE_VALID); values.put(COLUMN_DOCUMENT_TYPE, DOCUMENT_TYPE_DEVICE); values.put(Document.COLUMN_MIME_TYPE, Document.MIME_TYPE_DIR); values.put(Document.COLUMN_DISPLAY_NAME, name); values.putNull(Document.COLUMN_SUMMARY); values.putNull(Document.COLUMN_LAST_MODIFIED); values.put(Document.COLUMN_ICON, R.drawable.ic_root_mtp); values.put(Document.COLUMN_FLAGS, 0); long size = 0; for (final MtpRoot root : roots) { size += root.mMaxCapacity - root.mFreeSpace; } values.put(Document.COLUMN_SIZE, size); } /** * Gets {@link ContentValues} for the given root. * @param values {@link ContentValues} that receives values. * @param resources Resources used to get localized root name. * @param root Root to be converted {@link ContentValues}. */ static void getStorageDocumentValues( ContentValues values, Resources resources, String parentDocumentId, MtpRoot root) { static void getRootDocumentValues(ContentValues values, Resources resources, MtpRoot root) { values.clear(); values.put(COLUMN_DEVICE_ID, root.mDeviceId); values.put(COLUMN_STORAGE_ID, root.mStorageId); values.putNull(COLUMN_OBJECT_HANDLE); values.put(COLUMN_PARENT_DOCUMENT_ID, parentDocumentId); values.putNull(COLUMN_PARENT_DOCUMENT_ID); values.put(COLUMN_ROW_STATE, ROW_STATE_VALID); values.put(COLUMN_DOCUMENT_TYPE, DOCUMENT_TYPE_STORAGE); values.put(Document.COLUMN_MIME_TYPE, Document.MIME_TYPE_DIR); Loading @@ -415,7 +389,7 @@ class MtpDatabase { * @param parentId Parent document ID of the object. * @param info MTP object info. */ static void getObjectDocumentValues( static void getChildDocumentValues( ContentValues values, int deviceId, String parentId, MtpObjectInfo info) { values.clear(); final String mimeType = info.getFormat() == MtpConstants.FORMAT_ASSOCIATION ? Loading packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabaseConstants.java +29 −36 Original line number Diff line number Diff line Loading @@ -16,13 +16,9 @@ package com.android.mtp; import android.database.sqlite.SQLiteQueryBuilder; import android.provider.DocumentsContract.Document; import android.provider.DocumentsContract.Root; import java.util.HashMap; import java.util.Map; /** * Class containing MtpDatabase constants. */ Loading @@ -45,13 +41,9 @@ class MtpDatabaseConstants { static final String TABLE_ROOT_EXTRA = "RootExtra"; /** * 'FROM' closure of joining TABLE_DOCUMENTS and TABLE_ROOT_EXTRA. * View to join Documents and RootExtra tables to provide roots information. */ static final String JOIN_ROOTS = createJoinFromClosure( TABLE_DOCUMENTS, TABLE_ROOT_EXTRA, Document.COLUMN_DOCUMENT_ID, Root.COLUMN_ROOT_ID); static final String VIEW_ROOTS = "Roots"; static final String COLUMN_DEVICE_ID = "device_id"; static final String COLUMN_STORAGE_ID = "storage_id"; Loading Loading @@ -94,6 +86,8 @@ class MtpDatabaseConstants { /** * Document that represents a MTP device. * Note we have "device" document only when the device has multiple storage volumes. Otherwise * we regard the single "storage" document as root. */ static final int DOCUMENT_TYPE_DEVICE = 0; Loading Loading @@ -137,31 +131,30 @@ class MtpDatabaseConstants { Root.COLUMN_MIME_TYPES + " TEXT NOT NULL);"; /** * Map for columns names to provide DocumentContract.Root compatible columns. * @see SQLiteQueryBuilder#setProjectionMap(Map) * Creates a view to join Documents table and RootExtra table on their primary keys to * provide DocumentContract.Root equivalent information. */ static final Map<String, String> COLUMN_MAP_ROOTS; static { COLUMN_MAP_ROOTS = new HashMap<>(); COLUMN_MAP_ROOTS.put(Root.COLUMN_ROOT_ID, TABLE_ROOT_EXTRA + "." + Root.COLUMN_ROOT_ID); COLUMN_MAP_ROOTS.put(Root.COLUMN_FLAGS, TABLE_ROOT_EXTRA + "." + Root.COLUMN_FLAGS); COLUMN_MAP_ROOTS.put(Root.COLUMN_ICON, TABLE_DOCUMENTS + "." + Document.COLUMN_ICON); COLUMN_MAP_ROOTS.put( Root.COLUMN_TITLE, TABLE_DOCUMENTS + "." + Document.COLUMN_DISPLAY_NAME); COLUMN_MAP_ROOTS.put(Root.COLUMN_SUMMARY, TABLE_DOCUMENTS + "." + Document.COLUMN_SUMMARY); COLUMN_MAP_ROOTS.put( Root.COLUMN_DOCUMENT_ID, TABLE_DOCUMENTS + "." + Document.COLUMN_DOCUMENT_ID); COLUMN_MAP_ROOTS.put( Root.COLUMN_AVAILABLE_BYTES, TABLE_ROOT_EXTRA + "." + Root.COLUMN_AVAILABLE_BYTES); COLUMN_MAP_ROOTS.put( Root.COLUMN_CAPACITY_BYTES, TABLE_ROOT_EXTRA + "." + Root.COLUMN_CAPACITY_BYTES); COLUMN_MAP_ROOTS.put( Root.COLUMN_MIME_TYPES, TABLE_ROOT_EXTRA + "." + Root.COLUMN_MIME_TYPES); } private static String createJoinFromClosure( String table1, String table2, String column1, String column2) { return table1 + " INNER JOIN " + table2 + " ON " + table1 + "." + column1 + " = " + table2 + "." + column2; } static final String QUERY_CREATE_VIEW_ROOTS = "CREATE VIEW " + VIEW_ROOTS + " AS SELECT " + TABLE_DOCUMENTS + "." + Document.COLUMN_DOCUMENT_ID + " AS " + Root.COLUMN_ROOT_ID + "," + TABLE_ROOT_EXTRA + "." + Root.COLUMN_FLAGS + "," + TABLE_DOCUMENTS + "." + Document.COLUMN_ICON + " AS " + Root.COLUMN_ICON + "," + TABLE_DOCUMENTS + "." + Document.COLUMN_DISPLAY_NAME + " AS " + Root.COLUMN_TITLE + "," + TABLE_DOCUMENTS + "." + Document.COLUMN_SUMMARY + " AS " + Root.COLUMN_SUMMARY + "," + TABLE_DOCUMENTS + "." + Document.COLUMN_DOCUMENT_ID + " AS " + Root.COLUMN_DOCUMENT_ID + "," + TABLE_ROOT_EXTRA + "." + Root.COLUMN_AVAILABLE_BYTES + "," + TABLE_ROOT_EXTRA + "." + Root.COLUMN_CAPACITY_BYTES + "," + TABLE_ROOT_EXTRA + "." + Root.COLUMN_MIME_TYPES + "," + TABLE_DOCUMENTS + "." + COLUMN_ROW_STATE + " FROM " + TABLE_DOCUMENTS + " INNER JOIN " + TABLE_ROOT_EXTRA + " ON " + COLUMN_PARENT_DOCUMENT_ID + " IS NULL AND " + TABLE_DOCUMENTS + "." + Document.COLUMN_DOCUMENT_ID + "=" + TABLE_ROOT_EXTRA + "." + Root.COLUMN_ROOT_ID; } packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java +3 −0 Original line number Diff line number Diff line Loading @@ -190,6 +190,9 @@ public class MtpDocumentsProvider extends DocumentsProvider { getDocumentLoader(parentIdentifier).clearTask(parentIdentifier); notifyChildDocumentsChange(parentIdentifier.mDocumentId); } catch (IOException error) { for (final StackTraceElement element : error.getStackTrace()) { Log.e("hirono", element.toString()); } throw new FileNotFoundException(error.getMessage()); } } Loading packages/MtpDocumentsProvider/src/com/android/mtp/RootScanner.java +8 −27 Original line number Diff line number Diff line Loading @@ -7,11 +7,8 @@ import android.net.Uri; import android.os.Process; import android.provider.DocumentsContract; import android.util.Log; import android.util.SparseArray; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.FutureTask; Loading Loading @@ -109,42 +106,26 @@ final class RootScanner { int pollingCount = 0; while (!Thread.interrupted()) { final int[] deviceIds = mManager.getOpenedDeviceIds(); final Map<String, MtpRoot[]> rootsMap = new HashMap<>(); if (deviceIds.length == 0) { return; } boolean changed = false; // Update devices. mDatabase.getMapper().startAddingDocuments(null /* parentDocumentId */); for (final int deviceId : deviceIds) { for (int deviceId : deviceIds) { try { final MtpRoot[] roots = mManager.getRoots(deviceId); final String id = mDatabase.getMapper().putDeviceDocument( deviceId, mManager.getDeviceName(deviceId), roots); if (id != null) { if (mDatabase.getMapper().putRootDocuments(deviceId, mResources, roots)) { changed = true; rootsMap.put(id, roots); } } catch (IOException exception) { } catch (IOException | SQLiteException exception) { // The error may happen on the device. We would like to continue getting // roots for other devices. Log.e(MtpDocumentsProvider.TAG, exception.getMessage()); } } mDatabase.getMapper().stopAddingDocuments(null /* parentDocumentId */); // Update roots. for (final String documentId : rootsMap.keySet()) { mDatabase.getMapper().startAddingDocuments(documentId); if (mDatabase.getMapper().putRootDocuments( documentId, mResources, rootsMap.get(documentId))) { changed = true; } if (mDatabase.getMapper().stopAddingDocuments(documentId)) { if (mDatabase.getMapper().stopAddingDocuments(null /* parentDocumentId */)) { changed = true; } } if (changed) { notifyChange(); } Loading Loading
packages/MtpDocumentsProvider/src/com/android/mtp/Mapper.java +13 −34 Original line number Diff line number Diff line Loading @@ -42,7 +42,6 @@ import static com.android.mtp.MtpDatabase.strings; * Also see the comments of {@link MtpDatabase}. */ class Mapper { private static final String[] EMPTY_ARGS = new String[0]; private final MtpDatabase mDatabase; /** Loading @@ -56,43 +55,21 @@ class Mapper { mDatabase = database; } synchronized String putDeviceDocument(int deviceId, String name, MtpRoot[] roots) { final SQLiteDatabase database = mDatabase.getSQLiteDatabase(); Preconditions.checkState(mMappingMode.containsKey(/* no parent for root */ null)); database.beginTransaction(); try { final ContentValues[] valuesList = new ContentValues[1]; valuesList[0] = new ContentValues(); MtpDatabase.getDeviceDocumentValues(valuesList[0], deviceId, name, roots); putDocuments( valuesList, COLUMN_PARENT_DOCUMENT_ID + " IS NULL", EMPTY_ARGS, /* heuristic */ false, COLUMN_DEVICE_ID); database.setTransactionSuccessful(); return valuesList[0].getAsString(Document.COLUMN_DOCUMENT_ID); } finally { database.endTransaction(); } } /** * Puts root information to database. * @param parentDocumentId Document ID of device document. * @param deviceId Device ID * @param resources Resources required to localize root name. * @param roots List of root information. * @return If roots are added or removed from the database. */ synchronized boolean putRootDocuments( String parentDocumentId, Resources resources, MtpRoot[] roots) { synchronized boolean putRootDocuments(int deviceId, Resources resources, MtpRoot[] roots) { final SQLiteDatabase database = mDatabase.getSQLiteDatabase(); database.beginTransaction(); try { final boolean heuristic; final String mapColumn; Preconditions.checkState(mMappingMode.containsKey(parentDocumentId)); switch (mMappingMode.get(parentDocumentId)) { Preconditions.checkState(mMappingMode.containsKey(/* no parent for root */ null)); switch (mMappingMode.get(/* no parent for root */ null)) { case MAP_BY_MTP_IDENTIFIER: heuristic = false; mapColumn = COLUMN_STORAGE_ID; Loading @@ -106,14 +83,16 @@ class Mapper { } final ContentValues[] valuesList = new ContentValues[roots.length]; for (int i = 0; i < roots.length; i++) { if (roots[i].mDeviceId != deviceId) { throw new IllegalArgumentException(); } valuesList[i] = new ContentValues(); MtpDatabase.getStorageDocumentValues( valuesList[i], resources, parentDocumentId, roots[i]); MtpDatabase.getRootDocumentValues(valuesList[i], resources, roots[i]); } final boolean changed = putDocuments( valuesList, COLUMN_PARENT_DOCUMENT_ID + "=?", strings(parentDocumentId), COLUMN_PARENT_DOCUMENT_ID + " IS NULL", new String[0], heuristic, mapColumn); final ContentValues values = new ContentValues(); Loading Loading @@ -167,7 +146,7 @@ class Mapper { final ContentValues[] valuesList = new ContentValues[documents.length]; for (int i = 0; i < documents.length; i++) { valuesList[i] = new ContentValues(); MtpDatabase.getObjectDocumentValues( MtpDatabase.getChildDocumentValues( valuesList[i], deviceId, parentId, documents[i]); } putDocuments( Loading Loading @@ -214,7 +193,7 @@ class Mapper { args = strings(parentDocumentId); } else { selection = COLUMN_PARENT_DOCUMENT_ID + " IS NULL"; args = EMPTY_ARGS; args = new String[0]; } final SQLiteDatabase database = mDatabase.getSQLiteDatabase(); Loading Loading @@ -333,7 +312,7 @@ class Mapper { args = strings(parentId); } else { selection = COLUMN_PARENT_DOCUMENT_ID + " IS NULL"; args = EMPTY_ARGS; args = new String[0]; } final String groupKey; switch (mMappingMode.get(parentId)) { Loading
packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java +13 −39 Original line number Diff line number Diff line Loading @@ -22,7 +22,6 @@ import android.content.ContentValues; import android.content.Context; import android.content.res.Resources; import android.database.Cursor; import android.database.MatrixCursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteQueryBuilder; Loading @@ -36,9 +35,9 @@ import android.provider.DocumentsContract.Root; import com.android.internal.annotations.VisibleForTesting; import java.io.FileNotFoundException; import java.util.HashMap; import java.util.Map; import java.util.HashSet; import java.util.Objects; import java.util.Set; /** * Database for MTP objects. Loading Loading @@ -108,14 +107,11 @@ class MtpDatabase { * @return Database cursor. */ Cursor queryRoots(String[] columnNames) { final SQLiteQueryBuilder builder = new SQLiteQueryBuilder(); builder.setTables(JOIN_ROOTS); builder.setProjectionMap(COLUMN_MAP_ROOTS); return builder.query( mDatabase, return mDatabase.query( VIEW_ROOTS, columnNames, COLUMN_ROW_STATE + " IN (?, ?) AND " + COLUMN_DOCUMENT_TYPE + " = ?", strings(ROW_STATE_VALID, ROW_STATE_INVALIDATED, DOCUMENT_TYPE_STORAGE), COLUMN_ROW_STATE + " IN (?, ?)", strings(ROW_STATE_VALID, ROW_STATE_INVALIDATED), null, null, null); Loading @@ -132,8 +128,8 @@ class MtpDatabase { return mDatabase.query( TABLE_DOCUMENTS, columnNames, COLUMN_ROW_STATE + " IN (?, ?) AND " + COLUMN_DOCUMENT_TYPE + "=?", strings(ROW_STATE_VALID, ROW_STATE_INVALIDATED, DOCUMENT_TYPE_STORAGE), COLUMN_ROW_STATE + " IN (?, ?)", strings(ROW_STATE_VALID, ROW_STATE_INVALIDATED), null, null, null); Loading Loading @@ -220,7 +216,7 @@ class MtpDatabase { */ String putNewDocument(int deviceId, String parentDocumentId, MtpObjectInfo info) { final ContentValues values = new ContentValues(); getObjectDocumentValues(values, deviceId, parentDocumentId, info); getChildDocumentValues(values, deviceId, parentDocumentId, info); mDatabase.beginTransaction(); try { final long id = mDatabase.insert(TABLE_DOCUMENTS, null, values); Loading Loading @@ -348,6 +344,7 @@ class MtpDatabase { public void onCreate(SQLiteDatabase db) { db.execSQL(QUERY_CREATE_DOCUMENTS); db.execSQL(QUERY_CREATE_ROOT_EXTRA); db.execSQL(QUERY_CREATE_VIEW_ROOTS); } @Override Loading @@ -361,41 +358,18 @@ class MtpDatabase { context.deleteDatabase(DATABASE_NAME); } static void getDeviceDocumentValues( ContentValues values, int deviceId, String name, MtpRoot[] roots) { values.clear(); values.put(COLUMN_DEVICE_ID, deviceId); values.putNull(COLUMN_STORAGE_ID); values.putNull(COLUMN_OBJECT_HANDLE); values.putNull(COLUMN_PARENT_DOCUMENT_ID); values.put(COLUMN_ROW_STATE, ROW_STATE_VALID); values.put(COLUMN_DOCUMENT_TYPE, DOCUMENT_TYPE_DEVICE); values.put(Document.COLUMN_MIME_TYPE, Document.MIME_TYPE_DIR); values.put(Document.COLUMN_DISPLAY_NAME, name); values.putNull(Document.COLUMN_SUMMARY); values.putNull(Document.COLUMN_LAST_MODIFIED); values.put(Document.COLUMN_ICON, R.drawable.ic_root_mtp); values.put(Document.COLUMN_FLAGS, 0); long size = 0; for (final MtpRoot root : roots) { size += root.mMaxCapacity - root.mFreeSpace; } values.put(Document.COLUMN_SIZE, size); } /** * Gets {@link ContentValues} for the given root. * @param values {@link ContentValues} that receives values. * @param resources Resources used to get localized root name. * @param root Root to be converted {@link ContentValues}. */ static void getStorageDocumentValues( ContentValues values, Resources resources, String parentDocumentId, MtpRoot root) { static void getRootDocumentValues(ContentValues values, Resources resources, MtpRoot root) { values.clear(); values.put(COLUMN_DEVICE_ID, root.mDeviceId); values.put(COLUMN_STORAGE_ID, root.mStorageId); values.putNull(COLUMN_OBJECT_HANDLE); values.put(COLUMN_PARENT_DOCUMENT_ID, parentDocumentId); values.putNull(COLUMN_PARENT_DOCUMENT_ID); values.put(COLUMN_ROW_STATE, ROW_STATE_VALID); values.put(COLUMN_DOCUMENT_TYPE, DOCUMENT_TYPE_STORAGE); values.put(Document.COLUMN_MIME_TYPE, Document.MIME_TYPE_DIR); Loading @@ -415,7 +389,7 @@ class MtpDatabase { * @param parentId Parent document ID of the object. * @param info MTP object info. */ static void getObjectDocumentValues( static void getChildDocumentValues( ContentValues values, int deviceId, String parentId, MtpObjectInfo info) { values.clear(); final String mimeType = info.getFormat() == MtpConstants.FORMAT_ASSOCIATION ? Loading
packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabaseConstants.java +29 −36 Original line number Diff line number Diff line Loading @@ -16,13 +16,9 @@ package com.android.mtp; import android.database.sqlite.SQLiteQueryBuilder; import android.provider.DocumentsContract.Document; import android.provider.DocumentsContract.Root; import java.util.HashMap; import java.util.Map; /** * Class containing MtpDatabase constants. */ Loading @@ -45,13 +41,9 @@ class MtpDatabaseConstants { static final String TABLE_ROOT_EXTRA = "RootExtra"; /** * 'FROM' closure of joining TABLE_DOCUMENTS and TABLE_ROOT_EXTRA. * View to join Documents and RootExtra tables to provide roots information. */ static final String JOIN_ROOTS = createJoinFromClosure( TABLE_DOCUMENTS, TABLE_ROOT_EXTRA, Document.COLUMN_DOCUMENT_ID, Root.COLUMN_ROOT_ID); static final String VIEW_ROOTS = "Roots"; static final String COLUMN_DEVICE_ID = "device_id"; static final String COLUMN_STORAGE_ID = "storage_id"; Loading Loading @@ -94,6 +86,8 @@ class MtpDatabaseConstants { /** * Document that represents a MTP device. * Note we have "device" document only when the device has multiple storage volumes. Otherwise * we regard the single "storage" document as root. */ static final int DOCUMENT_TYPE_DEVICE = 0; Loading Loading @@ -137,31 +131,30 @@ class MtpDatabaseConstants { Root.COLUMN_MIME_TYPES + " TEXT NOT NULL);"; /** * Map for columns names to provide DocumentContract.Root compatible columns. * @see SQLiteQueryBuilder#setProjectionMap(Map) * Creates a view to join Documents table and RootExtra table on their primary keys to * provide DocumentContract.Root equivalent information. */ static final Map<String, String> COLUMN_MAP_ROOTS; static { COLUMN_MAP_ROOTS = new HashMap<>(); COLUMN_MAP_ROOTS.put(Root.COLUMN_ROOT_ID, TABLE_ROOT_EXTRA + "." + Root.COLUMN_ROOT_ID); COLUMN_MAP_ROOTS.put(Root.COLUMN_FLAGS, TABLE_ROOT_EXTRA + "." + Root.COLUMN_FLAGS); COLUMN_MAP_ROOTS.put(Root.COLUMN_ICON, TABLE_DOCUMENTS + "." + Document.COLUMN_ICON); COLUMN_MAP_ROOTS.put( Root.COLUMN_TITLE, TABLE_DOCUMENTS + "." + Document.COLUMN_DISPLAY_NAME); COLUMN_MAP_ROOTS.put(Root.COLUMN_SUMMARY, TABLE_DOCUMENTS + "." + Document.COLUMN_SUMMARY); COLUMN_MAP_ROOTS.put( Root.COLUMN_DOCUMENT_ID, TABLE_DOCUMENTS + "." + Document.COLUMN_DOCUMENT_ID); COLUMN_MAP_ROOTS.put( Root.COLUMN_AVAILABLE_BYTES, TABLE_ROOT_EXTRA + "." + Root.COLUMN_AVAILABLE_BYTES); COLUMN_MAP_ROOTS.put( Root.COLUMN_CAPACITY_BYTES, TABLE_ROOT_EXTRA + "." + Root.COLUMN_CAPACITY_BYTES); COLUMN_MAP_ROOTS.put( Root.COLUMN_MIME_TYPES, TABLE_ROOT_EXTRA + "." + Root.COLUMN_MIME_TYPES); } private static String createJoinFromClosure( String table1, String table2, String column1, String column2) { return table1 + " INNER JOIN " + table2 + " ON " + table1 + "." + column1 + " = " + table2 + "." + column2; } static final String QUERY_CREATE_VIEW_ROOTS = "CREATE VIEW " + VIEW_ROOTS + " AS SELECT " + TABLE_DOCUMENTS + "." + Document.COLUMN_DOCUMENT_ID + " AS " + Root.COLUMN_ROOT_ID + "," + TABLE_ROOT_EXTRA + "." + Root.COLUMN_FLAGS + "," + TABLE_DOCUMENTS + "." + Document.COLUMN_ICON + " AS " + Root.COLUMN_ICON + "," + TABLE_DOCUMENTS + "." + Document.COLUMN_DISPLAY_NAME + " AS " + Root.COLUMN_TITLE + "," + TABLE_DOCUMENTS + "." + Document.COLUMN_SUMMARY + " AS " + Root.COLUMN_SUMMARY + "," + TABLE_DOCUMENTS + "." + Document.COLUMN_DOCUMENT_ID + " AS " + Root.COLUMN_DOCUMENT_ID + "," + TABLE_ROOT_EXTRA + "." + Root.COLUMN_AVAILABLE_BYTES + "," + TABLE_ROOT_EXTRA + "." + Root.COLUMN_CAPACITY_BYTES + "," + TABLE_ROOT_EXTRA + "." + Root.COLUMN_MIME_TYPES + "," + TABLE_DOCUMENTS + "." + COLUMN_ROW_STATE + " FROM " + TABLE_DOCUMENTS + " INNER JOIN " + TABLE_ROOT_EXTRA + " ON " + COLUMN_PARENT_DOCUMENT_ID + " IS NULL AND " + TABLE_DOCUMENTS + "." + Document.COLUMN_DOCUMENT_ID + "=" + TABLE_ROOT_EXTRA + "." + Root.COLUMN_ROOT_ID; }
packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java +3 −0 Original line number Diff line number Diff line Loading @@ -190,6 +190,9 @@ public class MtpDocumentsProvider extends DocumentsProvider { getDocumentLoader(parentIdentifier).clearTask(parentIdentifier); notifyChildDocumentsChange(parentIdentifier.mDocumentId); } catch (IOException error) { for (final StackTraceElement element : error.getStackTrace()) { Log.e("hirono", element.toString()); } throw new FileNotFoundException(error.getMessage()); } } Loading
packages/MtpDocumentsProvider/src/com/android/mtp/RootScanner.java +8 −27 Original line number Diff line number Diff line Loading @@ -7,11 +7,8 @@ import android.net.Uri; import android.os.Process; import android.provider.DocumentsContract; import android.util.Log; import android.util.SparseArray; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.FutureTask; Loading Loading @@ -109,42 +106,26 @@ final class RootScanner { int pollingCount = 0; while (!Thread.interrupted()) { final int[] deviceIds = mManager.getOpenedDeviceIds(); final Map<String, MtpRoot[]> rootsMap = new HashMap<>(); if (deviceIds.length == 0) { return; } boolean changed = false; // Update devices. mDatabase.getMapper().startAddingDocuments(null /* parentDocumentId */); for (final int deviceId : deviceIds) { for (int deviceId : deviceIds) { try { final MtpRoot[] roots = mManager.getRoots(deviceId); final String id = mDatabase.getMapper().putDeviceDocument( deviceId, mManager.getDeviceName(deviceId), roots); if (id != null) { if (mDatabase.getMapper().putRootDocuments(deviceId, mResources, roots)) { changed = true; rootsMap.put(id, roots); } } catch (IOException exception) { } catch (IOException | SQLiteException exception) { // The error may happen on the device. We would like to continue getting // roots for other devices. Log.e(MtpDocumentsProvider.TAG, exception.getMessage()); } } mDatabase.getMapper().stopAddingDocuments(null /* parentDocumentId */); // Update roots. for (final String documentId : rootsMap.keySet()) { mDatabase.getMapper().startAddingDocuments(documentId); if (mDatabase.getMapper().putRootDocuments( documentId, mResources, rootsMap.get(documentId))) { changed = true; } if (mDatabase.getMapper().stopAddingDocuments(documentId)) { if (mDatabase.getMapper().stopAddingDocuments(null /* parentDocumentId */)) { changed = true; } } if (changed) { notifyChange(); } Loading