Loading packages/MtpDocumentsProvider/src/com/android/mtp/Mapper.java +92 −76 Original line number Diff line number Diff line Loading @@ -24,13 +24,13 @@ import android.database.sqlite.SQLiteDatabase; import android.mtp.MtpObjectInfo; import android.provider.DocumentsContract.Document; import android.provider.DocumentsContract.Root; import android.util.ArraySet; import android.util.Log; import com.android.internal.util.Preconditions; import java.io.FileNotFoundException; import java.util.HashMap; import java.util.Map; import java.util.Set; import static com.android.mtp.MtpDatabaseConstants.*; import static com.android.mtp.MtpDatabase.strings; Loading @@ -44,11 +44,9 @@ class Mapper { private final MtpDatabase mDatabase; /** * Mapping mode for a parent. The key is document ID of parent, or null for root documents. * Methods operate the state needs to be synchronized. * TODO: Replace this with unboxing int map. * IDs which currently Mapper operates mapping for. */ private final Map<String, Integer> mMappingMode = new HashMap<>(); private final Set<String> mInMappingIds = new ArraySet<>(); Mapper(MtpDatabase database) { mDatabase = database; Loading @@ -75,7 +73,7 @@ class Mapper { extraValuesList, COLUMN_PARENT_DOCUMENT_ID + " IS NULL", EMPTY_ARGS, Document.COLUMN_DISPLAY_NAME); strings(COLUMN_DEVICE_ID, COLUMN_MAPPING_KEY)); database.setTransactionSuccessful(); return changed; } finally { Loading @@ -96,18 +94,6 @@ class Mapper { final SQLiteDatabase database = mDatabase.getSQLiteDatabase(); database.beginTransaction(); try { final String mapColumn; Preconditions.checkState(mMappingMode.containsKey(parentDocumentId)); switch (mMappingMode.get(parentDocumentId)) { case MAP_BY_MTP_IDENTIFIER: mapColumn = COLUMN_STORAGE_ID; break; case MAP_BY_NAME: mapColumn = Document.COLUMN_DISPLAY_NAME; break; default: throw new Error("Unexpected map mode."); } final ContentValues[] valuesList = new ContentValues[roots.length]; final ContentValues[] extraValuesList = new ContentValues[roots.length]; for (int i = 0; i < roots.length; i++) { Loading @@ -122,7 +108,7 @@ class Mapper { extraValuesList, COLUMN_PARENT_DOCUMENT_ID + " = ?", strings(parentDocumentId), mapColumn); strings(COLUMN_STORAGE_ID, Document.COLUMN_DISPLAY_NAME)); database.setTransactionSuccessful(); return changed; Loading @@ -141,23 +127,10 @@ class Mapper { */ synchronized void putChildDocuments(int deviceId, String parentId, MtpObjectInfo[] documents) throws FileNotFoundException { final String mapColumn; Preconditions.checkState(mMappingMode.containsKey(parentId)); switch (mMappingMode.get(parentId)) { case MAP_BY_MTP_IDENTIFIER: mapColumn = COLUMN_OBJECT_HANDLE; break; case MAP_BY_NAME: mapColumn = Document.COLUMN_DISPLAY_NAME; break; default: throw new Error("Unexpected map mode."); } final ContentValues[] valuesList = new ContentValues[documents.length]; for (int i = 0; i < documents.length; i++) { valuesList[i] = new ContentValues(); MtpDatabase.getObjectDocumentValues( valuesList[i], deviceId, parentId, documents[i]); MtpDatabase.getObjectDocumentValues(valuesList[i], deviceId, parentId, documents[i]); } putDocuments( parentId, Loading @@ -165,14 +138,14 @@ class Mapper { null, COLUMN_PARENT_DOCUMENT_ID + " = ?", strings(parentId), mapColumn); strings(COLUMN_OBJECT_HANDLE, Document.COLUMN_DISPLAY_NAME)); } void clearMapping() { final SQLiteDatabase database = mDatabase.getSQLiteDatabase(); database.beginTransaction(); try { mMappingMode.clear(); mInMappingIds.clear(); // Disconnect all device rows. try { startAddingDocuments(null); Loading Loading @@ -211,7 +184,7 @@ class Mapper { database.beginTransaction(); try { getParentOrHaltMapping(parentDocumentId); Preconditions.checkState(!mMappingMode.containsKey(parentDocumentId)); Preconditions.checkState(!mInMappingIds.contains(parentDocumentId)); // Set all valid documents as invalidated. final ContentValues values = new ContentValues(); Loading @@ -222,15 +195,8 @@ class Mapper { selection + " AND " + COLUMN_ROW_STATE + " = ?", DatabaseUtils.appendSelectionArgs(args, strings(ROW_STATE_VALID))); // If we have rows that does not have MTP identifier, do heuristic mapping by name. final boolean useNameForResolving = DatabaseUtils.queryNumEntries( database, TABLE_DOCUMENTS, selection + " AND " + COLUMN_DEVICE_ID + " IS NULL", args) > 0; database.setTransactionSuccessful(); mMappingMode.put( parentDocumentId, useNameForResolving ? MAP_BY_NAME : MAP_BY_MTP_IDENTIFIER); mInMappingIds.add(parentDocumentId); } finally { database.endTransaction(); } Loading @@ -249,7 +215,7 @@ class Mapper { * @param rootExtraValuesList Values for root extra to be stored in the database. * @param selection SQL where closure to select rows that shares the same parent. * @param args Argument for selection SQL. * @return Whether it adds at least one new row that is not mapped with existing document ID. * @return Whether the database content is changed. * @throws FileNotFoundException When parentId is not registered in the database. */ private boolean putDocuments( Loading @@ -258,13 +224,15 @@ class Mapper { @Nullable ContentValues[] rootExtraValuesList, String selection, String[] args, String mappingKey) throws FileNotFoundException { String[] mappingKeys) throws FileNotFoundException { final SQLiteDatabase database = mDatabase.getSQLiteDatabase(); boolean added = false; boolean changed = false; database.beginTransaction(); try { getParentOrHaltMapping(parentId); Preconditions.checkState(mMappingMode.containsKey(parentId)); Preconditions.checkState(mInMappingIds.contains(parentId)); final ContentValues oldRowSnapshot = new ContentValues(); final ContentValues newRowSnapshot = new ContentValues(); for (int i = 0; i < valuesList.length; i++) { final ContentValues values = valuesList[i]; final ContentValues rootExtraValues; Loading @@ -273,29 +241,18 @@ class Mapper { } else { rootExtraValues = null; } final Cursor candidateCursor = database.query( TABLE_DOCUMENTS, strings(Document.COLUMN_DOCUMENT_ID), selection + " AND " + COLUMN_ROW_STATE + " IN (?, ?) AND " + mappingKey + "=?", DatabaseUtils.appendSelectionArgs( args, strings(ROW_STATE_INVALIDATED, ROW_STATE_DISCONNECTED, values.getAsString(mappingKey))), null, null, null, "1"); try { try (final Cursor candidateCursor = queryCandidate(selection, args, mappingKeys, values)) { final long rowId; if (candidateCursor.getCount() == 0) { if (candidateCursor == null) { rowId = database.insert(TABLE_DOCUMENTS, null, values); added = true; changed = true; } else { candidateCursor.moveToNext(); rowId = candidateCursor.getLong(0); if (!changed) { mDatabase.writeRowSnapshot(String.valueOf(rowId), oldRowSnapshot); } database.update( TABLE_DOCUMENTS, values, Loading @@ -309,13 +266,20 @@ class Mapper { rootExtraValues.put(Root.COLUMN_ROOT_ID, rowId); database.replace(TABLE_ROOT_EXTRA, null, rootExtraValues); } } finally { candidateCursor.close(); if (!changed) { mDatabase.writeRowSnapshot(String.valueOf(rowId), newRowSnapshot); // Put row state as string because SQLite returns snapshot values as string. oldRowSnapshot.put(COLUMN_ROW_STATE, String.valueOf(ROW_STATE_VALID)); if (!oldRowSnapshot.equals(newRowSnapshot)) { changed = true; } } } } database.setTransactionSuccessful(); return added; return changed; } finally { database.endTransaction(); } Loading Loading @@ -345,8 +309,8 @@ class Mapper { database.beginTransaction(); try { final Identifier parentIdentifier = getParentOrHaltMapping(parentId); Preconditions.checkState(mMappingMode.containsKey(parentId)); mMappingMode.remove(parentId); Preconditions.checkState(mInMappingIds.contains(parentId)); mInMappingIds.remove(parentId); boolean changed = false; // Delete/disconnect all invalidated rows that cannot be mapped. Loading Loading @@ -374,6 +338,58 @@ class Mapper { } } /** * Queries candidate for each mappingKey, and returns the first cursor that includes a * candidate. * * @param selection Pre-selection for candidate. * @param args Arguments for selection. * @param mappingKeys List of mapping key columns. * @param values Values of document that Mapper tries to map. * @return Cursor for mapping candidate or null when Mapper does not find any candidate. */ private @Nullable Cursor queryCandidate( String selection, String[] args, String[] mappingKeys, ContentValues values) { for (final String mappingKey : mappingKeys) { final Cursor candidateCursor = queryCandidate(selection, args, mappingKey, values); if (candidateCursor.getCount() == 0) { candidateCursor.close(); continue; } return candidateCursor; } return null; } /** * Looks for mapping candidate with given mappingKey. * * @param selection Pre-selection for candidate. * @param args Arguments for selection. * @param mappingKey Column name of mapping key. * @param values Values of document that Mapper tries to map. * @return Cursor for mapping candidate. */ private Cursor queryCandidate( String selection, String[] args, String mappingKey, ContentValues values) { final SQLiteDatabase database = mDatabase.getSQLiteDatabase(); return database.query( TABLE_DOCUMENTS, strings(Document.COLUMN_DOCUMENT_ID), selection + " AND " + COLUMN_ROW_STATE + " IN (?, ?) AND " + mappingKey + " = ?", DatabaseUtils.appendSelectionArgs( args, strings(ROW_STATE_INVALIDATED, ROW_STATE_DISCONNECTED, values.getAsString(mappingKey))), null, null, null, "1"); } /** * Returns the parent identifier from parent document ID if the parent ID is found in the * database. Otherwise it halts mapping and throws FileNotFoundException. Loading @@ -395,7 +411,7 @@ class Mapper { } return identifier; } catch (FileNotFoundException error) { mMappingMode.remove(parentId); mInMappingIds.remove(parentId); throw error; } } Loading packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java +20 −0 Original line number Diff line number Diff line Loading @@ -562,6 +562,25 @@ class MtpDatabase { } } void writeRowSnapshot(String documentId, ContentValues values) throws FileNotFoundException { try (final Cursor cursor = mDatabase.query( JOIN_ROOTS, strings("*"), SELECTION_DOCUMENT_ID, strings(documentId), null, null, null, "1")) { if (cursor.getCount() == 0) { throw new FileNotFoundException(); } cursor.moveToNext(); values.clear(); DatabaseUtils.cursorRowToContentValues(cursor, values); } } private static class OpenHelper extends SQLiteOpenHelper { public OpenHelper(Context context, int flags) { super(context, Loading Loading @@ -600,6 +619,7 @@ class MtpDatabase { values.putNull(COLUMN_PARENT_DOCUMENT_ID); values.put(COLUMN_ROW_STATE, ROW_STATE_VALID); values.put(COLUMN_DOCUMENT_TYPE, DOCUMENT_TYPE_DEVICE); values.put(COLUMN_MAPPING_KEY, device.deviceKey); values.put(Document.COLUMN_MIME_TYPE, Document.MIME_TYPE_DIR); values.put(Document.COLUMN_DISPLAY_NAME, device.name); values.putNull(Document.COLUMN_SUMMARY); Loading packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabaseConstants.java +4 −12 Original line number Diff line number Diff line Loading @@ -30,7 +30,7 @@ import java.util.Map; * Class containing MtpDatabase constants. */ class MtpDatabaseConstants { static final int DATABASE_VERSION = 3; static final int DATABASE_VERSION = 4; static final String DATABASE_NAME = "database"; static final int FLAG_DATABASE_IN_MEMORY = 1; Loading Loading @@ -62,6 +62,7 @@ class MtpDatabaseConstants { static final String COLUMN_PARENT_DOCUMENT_ID = "parent_document_id"; static final String COLUMN_DOCUMENT_TYPE = "document_type"; static final String COLUMN_ROW_STATE = "row_state"; static final String COLUMN_MAPPING_KEY = "column_mapping_key"; /** * The state represents that the row has a valid object handle. Loading @@ -83,16 +84,6 @@ class MtpDatabaseConstants { */ static final int ROW_STATE_DISCONNECTED = 2; /** * Mapping mode that uses MTP identifier to find corresponding rows. */ static final int MAP_BY_MTP_IDENTIFIER = 0; /** * Mapping mode that uses name to find corresponding rows. */ static final int MAP_BY_NAME = 1; @IntDef(value = { DOCUMENT_TYPE_DEVICE, DOCUMENT_TYPE_STORAGE, DOCUMENT_TYPE_OBJECT }) @Retention(RetentionPolicy.SOURCE) public @interface DocumentType {} Loading Loading @@ -125,6 +116,7 @@ class MtpDatabaseConstants { COLUMN_PARENT_DOCUMENT_ID + " INTEGER," + COLUMN_ROW_STATE + " INTEGER NOT NULL," + COLUMN_DOCUMENT_TYPE + " INTEGER NOT NULL," + COLUMN_MAPPING_KEY + " STRING," + Document.COLUMN_MIME_TYPE + " TEXT NOT NULL," + Document.COLUMN_DISPLAY_NAME + " TEXT NOT NULL," + Document.COLUMN_SUMMARY + " TEXT," + Loading Loading @@ -174,7 +166,7 @@ class MtpDatabaseConstants { private static String createJoinFromClosure( String table1, String table2, String column1, String column2) { return table1 + " INNER JOIN " + table2 + return table1 + " LEFT JOIN " + table2 + " ON " + table1 + "." + column1 + " = " + table2 + "." + column2; } } packages/MtpDocumentsProvider/src/com/android/mtp/MtpDeviceRecord.java +5 −2 Original line number Diff line number Diff line Loading @@ -21,17 +21,20 @@ import android.annotation.Nullable; class MtpDeviceRecord { public final int deviceId; public final String name; public final @Nullable String deviceKey; public final boolean opened; public final MtpRoot[] roots; public final @Nullable int[] operationsSupported; public final @Nullable int[] eventsSupported; MtpDeviceRecord(int deviceId, String name, boolean opened, MtpRoot[] roots, @Nullable int[] operationsSupported, @Nullable int[] eventsSupported) { MtpDeviceRecord(int deviceId, String name, @Nullable String deviceKey, boolean opened, MtpRoot[] roots, @Nullable int[] operationsSupported, @Nullable int[] eventsSupported) { this.deviceId = deviceId; this.name = name; this.opened = opened; this.roots = roots; this.deviceKey = deviceKey; this.operationsSupported = operationsSupported; this.eventsSupported = eventsSupported; } Loading packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java +3 −0 Original line number Diff line number Diff line Loading @@ -374,6 +374,9 @@ public class MtpDocumentsProvider extends DocumentsProvider { * Resumes root scanner to handle the update of device list. */ void resumeRootScanner() { if (DEBUG) { Log.d(MtpDocumentsProvider.TAG, "resumeRootScanner"); } mRootScanner.resume(); } Loading Loading
packages/MtpDocumentsProvider/src/com/android/mtp/Mapper.java +92 −76 Original line number Diff line number Diff line Loading @@ -24,13 +24,13 @@ import android.database.sqlite.SQLiteDatabase; import android.mtp.MtpObjectInfo; import android.provider.DocumentsContract.Document; import android.provider.DocumentsContract.Root; import android.util.ArraySet; import android.util.Log; import com.android.internal.util.Preconditions; import java.io.FileNotFoundException; import java.util.HashMap; import java.util.Map; import java.util.Set; import static com.android.mtp.MtpDatabaseConstants.*; import static com.android.mtp.MtpDatabase.strings; Loading @@ -44,11 +44,9 @@ class Mapper { private final MtpDatabase mDatabase; /** * Mapping mode for a parent. The key is document ID of parent, or null for root documents. * Methods operate the state needs to be synchronized. * TODO: Replace this with unboxing int map. * IDs which currently Mapper operates mapping for. */ private final Map<String, Integer> mMappingMode = new HashMap<>(); private final Set<String> mInMappingIds = new ArraySet<>(); Mapper(MtpDatabase database) { mDatabase = database; Loading @@ -75,7 +73,7 @@ class Mapper { extraValuesList, COLUMN_PARENT_DOCUMENT_ID + " IS NULL", EMPTY_ARGS, Document.COLUMN_DISPLAY_NAME); strings(COLUMN_DEVICE_ID, COLUMN_MAPPING_KEY)); database.setTransactionSuccessful(); return changed; } finally { Loading @@ -96,18 +94,6 @@ class Mapper { final SQLiteDatabase database = mDatabase.getSQLiteDatabase(); database.beginTransaction(); try { final String mapColumn; Preconditions.checkState(mMappingMode.containsKey(parentDocumentId)); switch (mMappingMode.get(parentDocumentId)) { case MAP_BY_MTP_IDENTIFIER: mapColumn = COLUMN_STORAGE_ID; break; case MAP_BY_NAME: mapColumn = Document.COLUMN_DISPLAY_NAME; break; default: throw new Error("Unexpected map mode."); } final ContentValues[] valuesList = new ContentValues[roots.length]; final ContentValues[] extraValuesList = new ContentValues[roots.length]; for (int i = 0; i < roots.length; i++) { Loading @@ -122,7 +108,7 @@ class Mapper { extraValuesList, COLUMN_PARENT_DOCUMENT_ID + " = ?", strings(parentDocumentId), mapColumn); strings(COLUMN_STORAGE_ID, Document.COLUMN_DISPLAY_NAME)); database.setTransactionSuccessful(); return changed; Loading @@ -141,23 +127,10 @@ class Mapper { */ synchronized void putChildDocuments(int deviceId, String parentId, MtpObjectInfo[] documents) throws FileNotFoundException { final String mapColumn; Preconditions.checkState(mMappingMode.containsKey(parentId)); switch (mMappingMode.get(parentId)) { case MAP_BY_MTP_IDENTIFIER: mapColumn = COLUMN_OBJECT_HANDLE; break; case MAP_BY_NAME: mapColumn = Document.COLUMN_DISPLAY_NAME; break; default: throw new Error("Unexpected map mode."); } final ContentValues[] valuesList = new ContentValues[documents.length]; for (int i = 0; i < documents.length; i++) { valuesList[i] = new ContentValues(); MtpDatabase.getObjectDocumentValues( valuesList[i], deviceId, parentId, documents[i]); MtpDatabase.getObjectDocumentValues(valuesList[i], deviceId, parentId, documents[i]); } putDocuments( parentId, Loading @@ -165,14 +138,14 @@ class Mapper { null, COLUMN_PARENT_DOCUMENT_ID + " = ?", strings(parentId), mapColumn); strings(COLUMN_OBJECT_HANDLE, Document.COLUMN_DISPLAY_NAME)); } void clearMapping() { final SQLiteDatabase database = mDatabase.getSQLiteDatabase(); database.beginTransaction(); try { mMappingMode.clear(); mInMappingIds.clear(); // Disconnect all device rows. try { startAddingDocuments(null); Loading Loading @@ -211,7 +184,7 @@ class Mapper { database.beginTransaction(); try { getParentOrHaltMapping(parentDocumentId); Preconditions.checkState(!mMappingMode.containsKey(parentDocumentId)); Preconditions.checkState(!mInMappingIds.contains(parentDocumentId)); // Set all valid documents as invalidated. final ContentValues values = new ContentValues(); Loading @@ -222,15 +195,8 @@ class Mapper { selection + " AND " + COLUMN_ROW_STATE + " = ?", DatabaseUtils.appendSelectionArgs(args, strings(ROW_STATE_VALID))); // If we have rows that does not have MTP identifier, do heuristic mapping by name. final boolean useNameForResolving = DatabaseUtils.queryNumEntries( database, TABLE_DOCUMENTS, selection + " AND " + COLUMN_DEVICE_ID + " IS NULL", args) > 0; database.setTransactionSuccessful(); mMappingMode.put( parentDocumentId, useNameForResolving ? MAP_BY_NAME : MAP_BY_MTP_IDENTIFIER); mInMappingIds.add(parentDocumentId); } finally { database.endTransaction(); } Loading @@ -249,7 +215,7 @@ class Mapper { * @param rootExtraValuesList Values for root extra to be stored in the database. * @param selection SQL where closure to select rows that shares the same parent. * @param args Argument for selection SQL. * @return Whether it adds at least one new row that is not mapped with existing document ID. * @return Whether the database content is changed. * @throws FileNotFoundException When parentId is not registered in the database. */ private boolean putDocuments( Loading @@ -258,13 +224,15 @@ class Mapper { @Nullable ContentValues[] rootExtraValuesList, String selection, String[] args, String mappingKey) throws FileNotFoundException { String[] mappingKeys) throws FileNotFoundException { final SQLiteDatabase database = mDatabase.getSQLiteDatabase(); boolean added = false; boolean changed = false; database.beginTransaction(); try { getParentOrHaltMapping(parentId); Preconditions.checkState(mMappingMode.containsKey(parentId)); Preconditions.checkState(mInMappingIds.contains(parentId)); final ContentValues oldRowSnapshot = new ContentValues(); final ContentValues newRowSnapshot = new ContentValues(); for (int i = 0; i < valuesList.length; i++) { final ContentValues values = valuesList[i]; final ContentValues rootExtraValues; Loading @@ -273,29 +241,18 @@ class Mapper { } else { rootExtraValues = null; } final Cursor candidateCursor = database.query( TABLE_DOCUMENTS, strings(Document.COLUMN_DOCUMENT_ID), selection + " AND " + COLUMN_ROW_STATE + " IN (?, ?) AND " + mappingKey + "=?", DatabaseUtils.appendSelectionArgs( args, strings(ROW_STATE_INVALIDATED, ROW_STATE_DISCONNECTED, values.getAsString(mappingKey))), null, null, null, "1"); try { try (final Cursor candidateCursor = queryCandidate(selection, args, mappingKeys, values)) { final long rowId; if (candidateCursor.getCount() == 0) { if (candidateCursor == null) { rowId = database.insert(TABLE_DOCUMENTS, null, values); added = true; changed = true; } else { candidateCursor.moveToNext(); rowId = candidateCursor.getLong(0); if (!changed) { mDatabase.writeRowSnapshot(String.valueOf(rowId), oldRowSnapshot); } database.update( TABLE_DOCUMENTS, values, Loading @@ -309,13 +266,20 @@ class Mapper { rootExtraValues.put(Root.COLUMN_ROOT_ID, rowId); database.replace(TABLE_ROOT_EXTRA, null, rootExtraValues); } } finally { candidateCursor.close(); if (!changed) { mDatabase.writeRowSnapshot(String.valueOf(rowId), newRowSnapshot); // Put row state as string because SQLite returns snapshot values as string. oldRowSnapshot.put(COLUMN_ROW_STATE, String.valueOf(ROW_STATE_VALID)); if (!oldRowSnapshot.equals(newRowSnapshot)) { changed = true; } } } } database.setTransactionSuccessful(); return added; return changed; } finally { database.endTransaction(); } Loading Loading @@ -345,8 +309,8 @@ class Mapper { database.beginTransaction(); try { final Identifier parentIdentifier = getParentOrHaltMapping(parentId); Preconditions.checkState(mMappingMode.containsKey(parentId)); mMappingMode.remove(parentId); Preconditions.checkState(mInMappingIds.contains(parentId)); mInMappingIds.remove(parentId); boolean changed = false; // Delete/disconnect all invalidated rows that cannot be mapped. Loading Loading @@ -374,6 +338,58 @@ class Mapper { } } /** * Queries candidate for each mappingKey, and returns the first cursor that includes a * candidate. * * @param selection Pre-selection for candidate. * @param args Arguments for selection. * @param mappingKeys List of mapping key columns. * @param values Values of document that Mapper tries to map. * @return Cursor for mapping candidate or null when Mapper does not find any candidate. */ private @Nullable Cursor queryCandidate( String selection, String[] args, String[] mappingKeys, ContentValues values) { for (final String mappingKey : mappingKeys) { final Cursor candidateCursor = queryCandidate(selection, args, mappingKey, values); if (candidateCursor.getCount() == 0) { candidateCursor.close(); continue; } return candidateCursor; } return null; } /** * Looks for mapping candidate with given mappingKey. * * @param selection Pre-selection for candidate. * @param args Arguments for selection. * @param mappingKey Column name of mapping key. * @param values Values of document that Mapper tries to map. * @return Cursor for mapping candidate. */ private Cursor queryCandidate( String selection, String[] args, String mappingKey, ContentValues values) { final SQLiteDatabase database = mDatabase.getSQLiteDatabase(); return database.query( TABLE_DOCUMENTS, strings(Document.COLUMN_DOCUMENT_ID), selection + " AND " + COLUMN_ROW_STATE + " IN (?, ?) AND " + mappingKey + " = ?", DatabaseUtils.appendSelectionArgs( args, strings(ROW_STATE_INVALIDATED, ROW_STATE_DISCONNECTED, values.getAsString(mappingKey))), null, null, null, "1"); } /** * Returns the parent identifier from parent document ID if the parent ID is found in the * database. Otherwise it halts mapping and throws FileNotFoundException. Loading @@ -395,7 +411,7 @@ class Mapper { } return identifier; } catch (FileNotFoundException error) { mMappingMode.remove(parentId); mInMappingIds.remove(parentId); throw error; } } Loading
packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java +20 −0 Original line number Diff line number Diff line Loading @@ -562,6 +562,25 @@ class MtpDatabase { } } void writeRowSnapshot(String documentId, ContentValues values) throws FileNotFoundException { try (final Cursor cursor = mDatabase.query( JOIN_ROOTS, strings("*"), SELECTION_DOCUMENT_ID, strings(documentId), null, null, null, "1")) { if (cursor.getCount() == 0) { throw new FileNotFoundException(); } cursor.moveToNext(); values.clear(); DatabaseUtils.cursorRowToContentValues(cursor, values); } } private static class OpenHelper extends SQLiteOpenHelper { public OpenHelper(Context context, int flags) { super(context, Loading Loading @@ -600,6 +619,7 @@ class MtpDatabase { values.putNull(COLUMN_PARENT_DOCUMENT_ID); values.put(COLUMN_ROW_STATE, ROW_STATE_VALID); values.put(COLUMN_DOCUMENT_TYPE, DOCUMENT_TYPE_DEVICE); values.put(COLUMN_MAPPING_KEY, device.deviceKey); values.put(Document.COLUMN_MIME_TYPE, Document.MIME_TYPE_DIR); values.put(Document.COLUMN_DISPLAY_NAME, device.name); values.putNull(Document.COLUMN_SUMMARY); Loading
packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabaseConstants.java +4 −12 Original line number Diff line number Diff line Loading @@ -30,7 +30,7 @@ import java.util.Map; * Class containing MtpDatabase constants. */ class MtpDatabaseConstants { static final int DATABASE_VERSION = 3; static final int DATABASE_VERSION = 4; static final String DATABASE_NAME = "database"; static final int FLAG_DATABASE_IN_MEMORY = 1; Loading Loading @@ -62,6 +62,7 @@ class MtpDatabaseConstants { static final String COLUMN_PARENT_DOCUMENT_ID = "parent_document_id"; static final String COLUMN_DOCUMENT_TYPE = "document_type"; static final String COLUMN_ROW_STATE = "row_state"; static final String COLUMN_MAPPING_KEY = "column_mapping_key"; /** * The state represents that the row has a valid object handle. Loading @@ -83,16 +84,6 @@ class MtpDatabaseConstants { */ static final int ROW_STATE_DISCONNECTED = 2; /** * Mapping mode that uses MTP identifier to find corresponding rows. */ static final int MAP_BY_MTP_IDENTIFIER = 0; /** * Mapping mode that uses name to find corresponding rows. */ static final int MAP_BY_NAME = 1; @IntDef(value = { DOCUMENT_TYPE_DEVICE, DOCUMENT_TYPE_STORAGE, DOCUMENT_TYPE_OBJECT }) @Retention(RetentionPolicy.SOURCE) public @interface DocumentType {} Loading Loading @@ -125,6 +116,7 @@ class MtpDatabaseConstants { COLUMN_PARENT_DOCUMENT_ID + " INTEGER," + COLUMN_ROW_STATE + " INTEGER NOT NULL," + COLUMN_DOCUMENT_TYPE + " INTEGER NOT NULL," + COLUMN_MAPPING_KEY + " STRING," + Document.COLUMN_MIME_TYPE + " TEXT NOT NULL," + Document.COLUMN_DISPLAY_NAME + " TEXT NOT NULL," + Document.COLUMN_SUMMARY + " TEXT," + Loading Loading @@ -174,7 +166,7 @@ class MtpDatabaseConstants { private static String createJoinFromClosure( String table1, String table2, String column1, String column2) { return table1 + " INNER JOIN " + table2 + return table1 + " LEFT JOIN " + table2 + " ON " + table1 + "." + column1 + " = " + table2 + "." + column2; } }
packages/MtpDocumentsProvider/src/com/android/mtp/MtpDeviceRecord.java +5 −2 Original line number Diff line number Diff line Loading @@ -21,17 +21,20 @@ import android.annotation.Nullable; class MtpDeviceRecord { public final int deviceId; public final String name; public final @Nullable String deviceKey; public final boolean opened; public final MtpRoot[] roots; public final @Nullable int[] operationsSupported; public final @Nullable int[] eventsSupported; MtpDeviceRecord(int deviceId, String name, boolean opened, MtpRoot[] roots, @Nullable int[] operationsSupported, @Nullable int[] eventsSupported) { MtpDeviceRecord(int deviceId, String name, @Nullable String deviceKey, boolean opened, MtpRoot[] roots, @Nullable int[] operationsSupported, @Nullable int[] eventsSupported) { this.deviceId = deviceId; this.name = name; this.opened = opened; this.roots = roots; this.deviceKey = deviceKey; this.operationsSupported = operationsSupported; this.eventsSupported = eventsSupported; } Loading
packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java +3 −0 Original line number Diff line number Diff line Loading @@ -374,6 +374,9 @@ public class MtpDocumentsProvider extends DocumentsProvider { * Resumes root scanner to handle the update of device list. */ void resumeRootScanner() { if (DEBUG) { Log.d(MtpDocumentsProvider.TAG, "resumeRootScanner"); } mRootScanner.resume(); } Loading