Adds methods for parsing outputs received from "adb shell content query".

Bug: 123528227
Test: unit tests
Change-Id: I6d41ee6253fc67abeacb8459b92560de97673c76
diff --git a/src/com/android/tradefed/device/contentprovider/ContentProviderHandler.java b/src/com/android/tradefed/device/contentprovider/ContentProviderHandler.java
index 55a733d..d972e1e 100644
--- a/src/com/android/tradefed/device/contentprovider/ContentProviderHandler.java
+++ b/src/com/android/tradefed/device/contentprovider/ContentProviderHandler.java
@@ -23,6 +23,7 @@
 import com.android.tradefed.util.FileUtil;
 import com.android.tradefed.util.StreamUtil;
 
+import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Strings;
 import com.google.common.net.UrlEscapers;
 
@@ -34,7 +35,11 @@
 import java.io.OutputStream;
 import java.io.UnsupportedEncodingException;
 import java.net.URLEncoder;
+import java.util.HashMap;
 import java.util.Set;
+import java.util.StringJoiner;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 /**
  * Handler that abstract the content provider interactions and allow to use the device side content
@@ -44,6 +49,22 @@
  * device.
  */
 public class ContentProviderHandler {
+    public static final String COLUMN_NAME = "name";
+    public static final String COLUMN_ABSOLUTE_PATH = "absolute_path";
+    public static final String COLUMN_DIRECTORY = "is_directory";
+    public static final String COLUMN_MIME_TYPE = "mime_type";
+    public static final String COLUMN_METADATA = "metadata";
+    public static final String QUERY_INFO_VALUE = "INFO";
+
+    // Has to be kept in sync with columns in ManagedFileContentProvider.java.
+    public static final String[] COLUMNS =
+            new String[] {
+                COLUMN_NAME,
+                COLUMN_ABSOLUTE_PATH,
+                COLUMN_DIRECTORY,
+                COLUMN_MIME_TYPE,
+                COLUMN_METADATA
+            };
 
     public static final String PACKAGE_NAME = "android.tradefed.contentprovider";
     public static final String CONTENT_PROVIDER_URI = "content://android.tradefed.contentprovider";
@@ -248,4 +269,33 @@
         }
         return String.format("\"%s/%s\"", CONTENT_PROVIDER_URI, escapedFilePath);
     }
+
+    /**
+     * Parses the String output of "adb shell content query" for a single row.
+     *
+     * @param row The entire row representing a single file/directory returned by the "adb shell
+     *     content query" command.
+     * @return Key-value map of column name to column value.
+     */
+    @VisibleForTesting
+    final HashMap<String, String> parseQueryResultRow(String row) {
+        HashMap<String, String> columnValues = new HashMap<>();
+
+        StringJoiner pattern = new StringJoiner(", ");
+        for (int i = 0; i < COLUMNS.length; i++) {
+            pattern.add(String.format("(%s=.*)", COLUMNS[i]));
+        }
+
+        Pattern p = Pattern.compile(pattern.toString());
+        Matcher m = p.matcher(row);
+        if (m.find()) {
+            for (int i = 1; i <= m.groupCount(); i++) {
+                String[] keyValue = m.group(i).split("=");
+                if (keyValue.length == 2) {
+                    columnValues.put(keyValue[0], keyValue[1]);
+                }
+            }
+        }
+        return columnValues;
+    }
 }
diff --git a/tests/src/com/android/tradefed/device/contentprovider/ContentProviderHandlerTest.java b/tests/src/com/android/tradefed/device/contentprovider/ContentProviderHandlerTest.java
index 0a53dfb..b50b5e5 100644
--- a/tests/src/com/android/tradefed/device/contentprovider/ContentProviderHandlerTest.java
+++ b/tests/src/com/android/tradefed/device/contentprovider/ContentProviderHandlerTest.java
@@ -39,6 +39,7 @@
 
 import java.io.File;
 import java.io.OutputStream;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Set;
 
@@ -240,6 +241,25 @@
                 espacedUrl);
     }
 
+    @Test
+    public void testParseQueryResultRow() {
+        String row =
+                "Row: 1 name=name spaced with , ,comma, "
+                        + "absolute_path=/storage/emulated/0/Alarms/name spaced with , ,comma, "
+                        + "is_directory=true, mime_type=NULL, metadata=NULL";
+
+        HashMap<String, String> columnValues = mProvider.parseQueryResultRow(row);
+
+        assertEquals(
+                columnValues.get(ContentProviderHandler.COLUMN_NAME), "name spaced with , ,comma");
+        assertEquals(
+                columnValues.get(ContentProviderHandler.COLUMN_ABSOLUTE_PATH),
+                "/storage/emulated/0/Alarms/name spaced with , ,comma");
+        assertEquals(columnValues.get(ContentProviderHandler.COLUMN_DIRECTORY), "true");
+        assertEquals(columnValues.get(ContentProviderHandler.COLUMN_MIME_TYPE), "NULL");
+        assertEquals(columnValues.get(ContentProviderHandler.COLUMN_METADATA), "NULL");
+    }
+
     private CommandResult mockSuccess() {
         CommandResult result = new CommandResult(CommandStatus.SUCCESS);
         result.setStderr("");