Integerate mapping methods for root/child documents into the same
methods.
The integrated methods will be used to add device documents as well as
root/child documents.
BUG=26175081
Change-Id: Ibf474cfbc41df402a2958e9efcdd0061f07f5ced
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/Mapper.java b/packages/MtpDocumentsProvider/src/com/android/mtp/Mapper.java
index 0d9d60c..15ebe99 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/Mapper.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/Mapper.java
@@ -18,6 +18,7 @@
import static com.android.mtp.MtpDatabaseConstants.*;
+import android.annotation.Nullable;
import android.content.ContentValues;
import android.content.res.Resources;
import android.database.Cursor;
@@ -36,7 +37,6 @@
import static com.android.mtp.MtpDatabase.strings;
-
/**
* Mapping operations for MtpDatabase.
* Also see the comments of {@link MtpDatabase}.
@@ -45,8 +45,9 @@
private final MtpDatabase mDatabase;
/**
- * Mapping mode for roots/documents where we start adding child documents.
+ * 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.
*/
private final Map<String, Integer> mMappingMode = new HashMap<>();
@@ -55,32 +56,6 @@
}
/**
- * Invokes {@link #startAddingDocuments} for root documents.
- * @param deviceId Device ID.
- */
- synchronized void startAddingRootDocuments(int deviceId) {
- final String mappingStateKey = getRootDocumentsMappingStateKey(deviceId);
- Preconditions.checkState(!mMappingMode.containsKey(mappingStateKey));
- mMappingMode.put(
- mappingStateKey,
- startAddingDocuments(
- SELECTION_ROOT_DOCUMENTS, Integer.toString(deviceId)));
- }
-
- /**
- * Invokes {@link #startAddingDocuments} for child of specific documents.
- * @param parentDocumentId Document ID for parent document.
- */
- @VisibleForTesting
- synchronized void startAddingChildDocuments(String parentDocumentId) {
- final String mappingStateKey = getChildDocumentsMappingStateKey(parentDocumentId);
- Preconditions.checkState(!mMappingMode.containsKey(mappingStateKey));
- mMappingMode.put(
- mappingStateKey,
- startAddingDocuments(SELECTION_CHILD_DOCUMENTS, parentDocumentId));
- }
-
- /**
* Puts root information to database.
* @param deviceId Device ID
* @param resources Resources required to localize root name.
@@ -93,9 +68,8 @@
try {
final boolean heuristic;
final String mapColumn;
- final String key = getRootDocumentsMappingStateKey(deviceId);
- Preconditions.checkState(mMappingMode.containsKey(key));
- switch (mMappingMode.get(key)) {
+ 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;
@@ -117,8 +91,8 @@
}
final boolean changed = putDocuments(
valuesList,
- SELECTION_ROOT_DOCUMENTS,
- Integer.toString(deviceId),
+ COLUMN_PARENT_DOCUMENT_ID + " IS NULL",
+ new String[0],
heuristic,
mapColumn);
final ContentValues values = new ContentValues();
@@ -156,9 +130,8 @@
synchronized void putChildDocuments(int deviceId, String parentId, MtpObjectInfo[] documents) {
final boolean heuristic;
final String mapColumn;
- final String key = getChildDocumentsMappingStateKey(parentId);
- Preconditions.checkState(mMappingMode.containsKey(key));
- switch (mMappingMode.get(key)) {
+ Preconditions.checkState(mMappingMode.containsKey(parentId));
+ switch (mMappingMode.get(parentId)) {
case MAP_BY_MTP_IDENTIFIER:
heuristic = false;
mapColumn = COLUMN_OBJECT_HANDLE;
@@ -177,59 +150,11 @@
valuesList[i], deviceId, parentId, documents[i]);
}
putDocuments(
- valuesList, SELECTION_CHILD_DOCUMENTS, parentId, heuristic, mapColumn);
- }
-
- /**
- * Stops adding root documents.
- * @param deviceId Device ID.
- * @return True if new rows are added/removed.
- */
- synchronized boolean stopAddingRootDocuments(int deviceId) {
- final String key = getRootDocumentsMappingStateKey(deviceId);
- Preconditions.checkState(mMappingMode.containsKey(key));
- switch (mMappingMode.get(key)) {
- case MAP_BY_MTP_IDENTIFIER:
- mMappingMode.remove(key);
- return stopAddingDocuments(
- SELECTION_ROOT_DOCUMENTS,
- Integer.toString(deviceId),
- COLUMN_STORAGE_ID);
- case MAP_BY_NAME:
- mMappingMode.remove(key);
- return stopAddingDocuments(
- SELECTION_ROOT_DOCUMENTS,
- Integer.toString(deviceId),
- Document.COLUMN_DISPLAY_NAME);
- default:
- throw new Error("Unexpected mapping state.");
- }
- }
-
- /**
- * Stops adding documents under the parent.
- * @param parentId Document ID of the parent.
- */
- synchronized void stopAddingChildDocuments(String parentId) {
- final String key = getChildDocumentsMappingStateKey(parentId);
- Preconditions.checkState(mMappingMode.containsKey(key));
- switch (mMappingMode.get(key)) {
- case MAP_BY_MTP_IDENTIFIER:
- stopAddingDocuments(
- SELECTION_CHILD_DOCUMENTS,
- parentId,
- COLUMN_OBJECT_HANDLE);
- break;
- case MAP_BY_NAME:
- stopAddingDocuments(
- SELECTION_CHILD_DOCUMENTS,
- parentId,
- Document.COLUMN_DISPLAY_NAME);
- break;
- default:
- throw new Error("Unexpected mapping state.");
- }
- mMappingMode.remove(key);
+ valuesList,
+ COLUMN_PARENT_DOCUMENT_ID + "=?",
+ strings(parentId),
+ heuristic,
+ mapColumn);
}
@VisibleForTesting
@@ -257,31 +182,42 @@
* identifier or not. If all the documents have MTP identifier, it uses the identifier to find
* a corresponding existing row. Otherwise it does heuristic.
*
- * @param selection Query matches valid documents.
- * @param arg Argument for selection.
- * @return Mapping mode.
+ * @param parentDocumentId Parent document ID or NULL for root documents.
*/
- private int startAddingDocuments(String selection, String arg) {
+ void startAddingDocuments(@Nullable String parentDocumentId) {
+ Preconditions.checkState(!mMappingMode.containsKey(parentDocumentId));
+ final String selection;
+ final String[] args;
+ if (parentDocumentId != null) {
+ selection = COLUMN_PARENT_DOCUMENT_ID + " = ?";
+ args = strings(parentDocumentId);
+ } else {
+ selection = COLUMN_PARENT_DOCUMENT_ID + " IS NULL";
+ args = new String[0];
+ }
+
final SQLiteDatabase database = mDatabase.getSQLiteDatabase();
database.beginTransaction();
try {
// Delete all pending rows.
mDatabase.deleteDocumentsAndRootsRecursively(
- selection + " AND " + COLUMN_ROW_STATE + "=?", strings(arg, ROW_STATE_PENDING));
+ selection + " AND " + COLUMN_ROW_STATE + "=?",
+ DatabaseUtils.appendSelectionArgs(args, strings(ROW_STATE_PENDING)));
// Set all documents as invalidated.
final ContentValues values = new ContentValues();
values.put(COLUMN_ROW_STATE, ROW_STATE_INVALIDATED);
- database.update(TABLE_DOCUMENTS, values, selection, new String[] { arg });
+ database.update(TABLE_DOCUMENTS, values, selection, args);
// 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_STORAGE_ID + " IS NULL",
- new String[] { arg }) > 0;
+ args) > 0;
database.setTransactionSuccessful();
- return useNameForResolving ? MAP_BY_NAME : MAP_BY_MTP_IDENTIFIER;
+ mMappingMode.put(
+ parentDocumentId, useNameForResolving ? MAP_BY_NAME : MAP_BY_MTP_IDENTIFIER);
} finally {
database.endTransaction();
}
@@ -292,19 +228,19 @@
* If the mapping mode is not heuristic, it just adds the rows to the database or updates the
* existing rows with the new values. If the mapping mode is heuristic, it adds some new rows as
* 'pending' state when that rows may be corresponding to existing 'invalidated' rows. Then
- * {@link #stopAddingDocuments(String, String, String)} turns the pending rows into 'valid'
+ * {@link #stopAddingDocuments(String, String[], String)} turns the pending rows into 'valid'
* rows. If the methods adds rows to database, it updates valueList with correct document ID.
*
* @param valuesList Values for documents to be stored in the database.
* @param selection SQL where closure to select rows that shares the same parent.
- * @param arg Argument for selection SQL.
+ * @param args Argument for selection SQL.
* @param heuristic Whether the mapping mode is heuristic.
* @return Whether the method adds new rows.
*/
private boolean putDocuments(
ContentValues[] valuesList,
String selection,
- String arg,
+ String[] args,
boolean heuristic,
String mappingKey) {
final SQLiteDatabase database = mDatabase.getSQLiteDatabase();
@@ -318,7 +254,9 @@
selection + " AND " +
COLUMN_ROW_STATE + "=? AND " +
mappingKey + "=?",
- strings(arg, ROW_STATE_INVALIDATED, values.getAsString(mappingKey)),
+ DatabaseUtils.appendSelectionArgs(
+ args,
+ strings(ROW_STATE_INVALIDATED, values.getAsString(mappingKey))),
null,
null,
null,
@@ -362,12 +300,32 @@
* Maps 'pending' document and 'invalidated' document that shares the same column of groupKey.
* If the database does not find corresponding 'invalidated' document, it just removes
* 'invalidated' document from the database.
- * @param selection Query to select rows for resolving.
- * @param arg Argument for selection SQL.
- * @param groupKey Column name used to find corresponding rows.
+ * @param parentId Parent document ID or null for root documents.
* @return Whether the methods adds or removed visible rows.
*/
- private boolean stopAddingDocuments(String selection, String arg, String groupKey) {
+ boolean stopAddingDocuments(@Nullable String parentId) {
+ Preconditions.checkState(mMappingMode.containsKey(parentId));
+ final String selection;
+ final String[] args;
+ if (parentId != null) {
+ selection = COLUMN_PARENT_DOCUMENT_ID + "=?";
+ args = strings(parentId);
+ } else {
+ selection = COLUMN_PARENT_DOCUMENT_ID + " IS NULL";
+ args = new String[0];
+ }
+ final String groupKey;
+ switch (mMappingMode.get(parentId)) {
+ case MAP_BY_MTP_IDENTIFIER:
+ groupKey = parentId != null ? COLUMN_OBJECT_HANDLE : COLUMN_STORAGE_ID;
+ break;
+ case MAP_BY_NAME:
+ groupKey = Document.COLUMN_DISPLAY_NAME;
+ break;
+ default:
+ throw new Error("Unexpected mapping state.");
+ }
+ mMappingMode.remove(parentId);
final SQLiteDatabase database = mDatabase.getSQLiteDatabase();
database.beginTransaction();
try {
@@ -390,7 +348,7 @@
"group_concat(" + pendingIdQuery + ")"
},
selection,
- strings(arg),
+ args,
groupKey,
"count(" + invalidatedIdQuery + ") = 1 AND count(" + pendingIdQuery + ") = 1",
null);
@@ -439,7 +397,7 @@
// Delete all invalidated rows that cannot be mapped.
if (mDatabase.deleteDocumentsAndRootsRecursively(
COLUMN_ROW_STATE + " = ? AND " + selection,
- strings(ROW_STATE_INVALIDATED, arg))) {
+ DatabaseUtils.appendSelectionArgs(strings(ROW_STATE_INVALIDATED), args))) {
changed = true;
}
@@ -452,7 +410,7 @@
TABLE_DOCUMENTS,
values,
COLUMN_ROW_STATE + " = ? AND " + selection,
- strings(ROW_STATE_PENDING, arg)) != 0) {
+ DatabaseUtils.appendSelectionArgs(strings(ROW_STATE_PENDING), args)) != 0) {
changed = true;
}
database.setTransactionSuccessful();
@@ -494,20 +452,4 @@
return "CASE WHEN " + COLUMN_ROW_STATE + " = " + Integer.toString(state) +
" THEN " + a + " ELSE NULL END";
}
-
- /**
- * @param deviceId Device ID.
- * @return Key for {@link #mMappingMode}.
- */
- private static String getRootDocumentsMappingStateKey(int deviceId) {
- return "RootDocuments/" + deviceId;
- }
-
- /**
- * @param parentDocumentId Document ID for the parent document.
- * @return Key for {@link #mMappingMode}.
- */
- private static String getChildDocumentsMappingStateKey(String parentDocumentId) {
- return "ChildDocuments/" + parentDocumentId;
- }
}