Merge "Index SliceType and Official Platform flag" into pi-dev
diff --git a/res/xml/power_usage_summary.xml b/res/xml/power_usage_summary.xml
index 22c9edc..1f3e415 100644
--- a/res/xml/power_usage_summary.xml
+++ b/res/xml/power_usage_summary.xml
@@ -37,7 +37,8 @@
             android:fragment="com.android.settings.fuelgauge.batterysaver.BatterySaverSettings"
             android:key="battery_saver_summary"
             android:title="@string/battery_saver"
-            settings:controller="com.android.settings.fuelgauge.BatterySaverController"/>
+            settings:controller="com.android.settings.fuelgauge.BatterySaverController"
+            settings:platform_slice="true"/>
 
         <Preference
             android:fragment="com.android.settings.fuelgauge.SmartBatterySettings"
diff --git a/src/com/android/settings/slices/SliceBuilderUtils.java b/src/com/android/settings/slices/SliceBuilderUtils.java
index a1f27d1..49972a8 100644
--- a/src/com/android/settings/slices/SliceBuilderUtils.java
+++ b/src/com/android/settings/slices/SliceBuilderUtils.java
@@ -26,6 +26,7 @@
 import android.net.Uri;
 import android.provider.SettingsSlicesContract;
 import android.text.TextUtils;
+import android.util.Pair;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.settings.R;
@@ -92,6 +93,38 @@
     }
 
     /**
+     * Splits the Settings Slice Uri path into its two expected components:
+     * - intent/action
+     * - key
+     * <p>
+     * Examples of valid paths are:
+     * - intent/wifi
+     * - intent/bluetooth
+     * - action/wifi
+     * - action/accessibility/servicename
+     *
+     * @param uri of the Slice. Follows pattern outlined in {@link SettingsSliceProvider}.
+     * @return Pair whose first element {@code true} if the path is prepended with "action", and
+     * second is a key.
+     */
+    public static Pair<Boolean, String> getPathData(Uri uri) {
+        final String path = uri.getPath();
+        final String[] split = path.split("/", 3);
+
+        // Split should be: [{}, SLICE_TYPE, KEY].
+        // Example: "/action/wifi" -> [{}, "action", "wifi"]
+        //          "/action/longer/path" -> [{}, "action", "longer/path"]
+        if (split.length != 3) {
+            throw new IllegalArgumentException("Uri (" + uri + ") has incomplete path: " + path);
+        }
+
+        final boolean isInline = TextUtils.equals(SettingsSlicesContract.PATH_SETTING_ACTION,
+                split[1]);
+
+        return new Pair<>(isInline, split[2]);
+    }
+
+    /**
      * Looks at the {@link SliceData#preferenceController} from {@param sliceData} and attempts to
      * build an {@link AbstractPreferenceController}.
      */
diff --git a/src/com/android/settings/slices/SlicesDatabaseAccessor.java b/src/com/android/settings/slices/SlicesDatabaseAccessor.java
index acd296b..82b3506 100644
--- a/src/com/android/settings/slices/SlicesDatabaseAccessor.java
+++ b/src/com/android/settings/slices/SlicesDatabaseAccessor.java
@@ -24,6 +24,7 @@
 
 import android.content.Context;
 import android.os.Binder;
+import android.util.Pair;
 
 import com.android.settings.overlay.FeatureFactory;
 import com.android.settings.slices.SlicesDatabaseHelper.IndexColumns;
@@ -35,7 +36,7 @@
  */
 public class SlicesDatabaseAccessor {
 
-    public static final String[] SELECT_COLUMNS = {
+    public static final String[] SELECT_COLUMNS_ALL = {
             IndexColumns.KEY,
             IndexColumns.TITLE,
             IndexColumns.SUMMARY,
@@ -43,8 +44,13 @@
             IndexColumns.ICON_RESOURCE,
             IndexColumns.FRAGMENT,
             IndexColumns.CONTROLLER,
+            IndexColumns.PLATFORM_SLICE,
+            IndexColumns.SLICE_TYPE,
     };
 
+    // Cursor value for boolean true
+    private final int TRUE = 1;
+
     Context mContext;
 
     public SlicesDatabaseAccessor(Context context) {
@@ -58,9 +64,9 @@
      * Used when building a {@link Slice}.
      */
     public SliceData getSliceDataFromUri(Uri uri) {
-        String key = uri.getLastPathSegment();
-        Cursor cursor = getIndexedSliceData(key);
-        return buildSliceData(cursor, uri);
+        Pair<Boolean, String> pathData = SliceBuilderUtils.getPathData(uri);
+        Cursor cursor = getIndexedSliceData(pathData.second /* key */);
+        return buildSliceData(cursor, uri, pathData.first /* isIntentOnly */);
     }
 
     /**
@@ -70,18 +76,18 @@
      */
     public SliceData getSliceDataFromKey(String key) {
         Cursor cursor = getIndexedSliceData(key);
-        return buildSliceData(cursor, null /* uri */);
+        return buildSliceData(cursor, null /* uri */, false /* isInlineOnly */);
     }
 
     private Cursor getIndexedSliceData(String path) {
         verifyIndexing();
 
-        final String whereClause = buildWhereClause();
+        final String whereClause = buildKeyMatchWhereClause();
         final SlicesDatabaseHelper helper = SlicesDatabaseHelper.getInstance(mContext);
         final SQLiteDatabase database = helper.getReadableDatabase();
         final String[] selection = new String[]{path};
 
-        Cursor resultCursor = database.query(TABLE_SLICES_INDEX, SELECT_COLUMNS, whereClause,
+        Cursor resultCursor = database.query(TABLE_SLICES_INDEX, SELECT_COLUMNS_ALL, whereClause,
                 selection, null /* groupBy */, null /* having */, null /* orderBy */);
 
         int numResults = resultCursor.getCount();
@@ -99,13 +105,13 @@
         return resultCursor;
     }
 
-    private String buildWhereClause() {
+    private String buildKeyMatchWhereClause() {
         return new StringBuilder(IndexColumns.KEY)
                 .append(" = ?")
                 .toString();
     }
 
-    private SliceData buildSliceData(Cursor cursor, Uri uri) {
+    private SliceData buildSliceData(Cursor cursor, Uri uri, boolean isInlineOnly) {
         final String key = cursor.getString(cursor.getColumnIndex(IndexColumns.KEY));
         final String title = cursor.getString(cursor.getColumnIndex(IndexColumns.TITLE));
         final String summary = cursor.getString(cursor.getColumnIndex(IndexColumns.SUMMARY));
@@ -116,6 +122,14 @@
                 cursor.getColumnIndex(IndexColumns.FRAGMENT));
         final String controllerClassName = cursor.getString(
                 cursor.getColumnIndex(IndexColumns.CONTROLLER));
+        final boolean isPlatformDefined = cursor.getInt(
+                cursor.getColumnIndex(IndexColumns.PLATFORM_SLICE)) == TRUE;
+        int sliceType = cursor.getInt(
+                cursor.getColumnIndex(IndexColumns.SLICE_TYPE));
+
+        if (!isInlineOnly) {
+            sliceType = SliceData.SliceType.INTENT;
+        }
 
         return new SliceData.Builder()
                 .setKey(key)
@@ -126,6 +140,8 @@
                 .setFragmentName(fragmentClassName)
                 .setPreferenceControllerClassName(controllerClassName)
                 .setUri(uri)
+                .setPlatformDefined(isPlatformDefined)
+                .setSliceType(sliceType)
                 .build();
     }
 
diff --git a/src/com/android/settings/slices/SlicesDatabaseHelper.java b/src/com/android/settings/slices/SlicesDatabaseHelper.java
index 627c62e..4334665 100644
--- a/src/com/android/settings/slices/SlicesDatabaseHelper.java
+++ b/src/com/android/settings/slices/SlicesDatabaseHelper.java
@@ -78,6 +78,16 @@
          * {@link com.android.settings.core.BasePreferenceController}.
          */
         String CONTROLLER = "controller";
+
+        /**
+         * Boolean flag, {@code true} when the Slice is officially platform-supported.
+         */
+        String PLATFORM_SLICE = "platform_slice";
+
+        /**
+         * {@link SliceData.SliceType} representing the inline type of the result.
+         */
+        String SLICE_TYPE = "slice_type";
     }
 
     private static final String CREATE_SLICES_TABLE =
@@ -96,6 +106,10 @@
                     IndexColumns.FRAGMENT +
                     ", " +
                     IndexColumns.CONTROLLER +
+                    ", " +
+                    IndexColumns.PLATFORM_SLICE +
+                    ", " +
+                    IndexColumns.SLICE_TYPE+
                     ");";
 
     private final Context mContext;
diff --git a/src/com/android/settings/slices/SlicesIndexer.java b/src/com/android/settings/slices/SlicesIndexer.java
index a92388a..d7de7bc 100644
--- a/src/com/android/settings/slices/SlicesIndexer.java
+++ b/src/com/android/settings/slices/SlicesIndexer.java
@@ -108,6 +108,8 @@
             values.put(IndexColumns.ICON_RESOURCE, dataRow.getIconResource());
             values.put(IndexColumns.FRAGMENT, dataRow.getFragmentClassName());
             values.put(IndexColumns.CONTROLLER, dataRow.getPreferenceController());
+            values.put(IndexColumns.PLATFORM_SLICE, dataRow.isPlatformDefined());
+            values.put(IndexColumns.SLICE_TYPE, dataRow.getSliceType());
 
             database.replaceOrThrow(Tables.TABLE_SLICES_INDEX, null /* nullColumnHack */,
                     values);
diff --git a/tests/robotests/src/com/android/settings/core/PreferenceXmlParserUtilTest.java b/tests/robotests/src/com/android/settings/core/PreferenceXmlParserUtilsTest.java
similarity index 99%
rename from tests/robotests/src/com/android/settings/core/PreferenceXmlParserUtilTest.java
rename to tests/robotests/src/com/android/settings/core/PreferenceXmlParserUtilsTest.java
index 458bc02..c96cebd 100644
--- a/tests/robotests/src/com/android/settings/core/PreferenceXmlParserUtilTest.java
+++ b/tests/robotests/src/com/android/settings/core/PreferenceXmlParserUtilsTest.java
@@ -48,7 +48,7 @@
  * with another preference with a matchin replacement attribute.
  */
 @RunWith(SettingsRobolectricTestRunner.class)
-public class PreferenceXmlParserUtilTest {
+public class PreferenceXmlParserUtilsTest {
 
     private Context mContext;
 
diff --git a/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java b/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java
index 8ddd48a..d54d16f 100644
--- a/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java
@@ -82,7 +82,7 @@
 
     @Test
     public void testInitialSliceReturned_emptySlice() {
-        insertSpecialCase(INTENT_PATH);
+        insertSpecialCase(KEY);
         Uri uri = SliceBuilderUtils.getUri(INTENT_PATH, false);
         Slice slice = mProvider.onBindSlice(uri);
 
@@ -93,7 +93,7 @@
     @Test
     public void testLoadSlice_returnsSliceFromAccessor() {
         insertSpecialCase(KEY);
-        Uri uri = SliceBuilderUtils.getUri(KEY, false);
+        Uri uri = SliceBuilderUtils.getUri(INTENT_PATH, false);
 
         mProvider.loadSlice(uri);
         SliceData data = mProvider.mSliceDataCache.get(uri);
diff --git a/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java b/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java
index 39b381d..869ba48 100644
--- a/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java
@@ -24,6 +24,7 @@
 import android.content.Context;
 import android.net.Uri;
 import android.provider.SettingsSlicesContract;
+import android.util.Pair;
 
 import com.android.settings.R;
 import com.android.settings.core.BasePreferenceController;
@@ -188,6 +189,59 @@
         assertThat(summary).isEqualTo(data.getScreenTitle());
     }
 
+    @Test
+    public void getPathData_splitsIntentUri() {
+        Uri uri = new Uri.Builder()
+                .authority(SettingsSliceProvider.SLICE_AUTHORITY)
+                .appendPath(SettingsSlicesContract.PATH_SETTING_INTENT)
+                .appendPath(KEY)
+                .build();
+
+        Pair<Boolean, String> pathPair = SliceBuilderUtils.getPathData(uri);
+
+        assertThat(pathPair.first).isFalse();
+        assertThat(pathPair.second).isEqualTo(KEY);
+    }
+
+    @Test
+    public void getPathData_splitsActionUri() {
+        Uri uri = new Uri.Builder()
+                .authority(SettingsSliceProvider.SLICE_AUTHORITY)
+                .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
+                .appendPath(KEY)
+                .build();
+
+        Pair<Boolean, String> pathPair = SliceBuilderUtils.getPathData(uri);
+
+        assertThat(pathPair.first).isTrue();
+        assertThat(pathPair.second).isEqualTo(KEY);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void getPathData_noKey_returnsNull() {
+        Uri uri = new Uri.Builder()
+                .authority(SettingsSliceProvider.SLICE_AUTHORITY)
+                .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
+                .build();
+
+        SliceBuilderUtils.getPathData(uri);
+    }
+
+    @Test
+    public void getPathData_extraArg_returnsNull() {
+        Uri uri = new Uri.Builder()
+                .authority(SettingsSliceProvider.SLICE_AUTHORITY)
+                .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
+                .appendPath(KEY)
+                .appendPath(KEY)
+                .build();
+
+        Pair<Boolean, String> pathPair = SliceBuilderUtils.getPathData(uri);
+
+        assertThat(pathPair.first).isTrue();
+        assertThat(pathPair.second).isEqualTo(KEY + "/" + KEY);
+    }
+
     private SliceData getDummyData() {
         return getDummyData(PREF_CONTROLLER, SUMMARY);
     }
diff --git a/tests/robotests/src/com/android/settings/slices/SlicesDatabaseAccessorTest.java b/tests/robotests/src/com/android/settings/slices/SlicesDatabaseAccessorTest.java
index 331058c..77c9891 100644
--- a/tests/robotests/src/com/android/settings/slices/SlicesDatabaseAccessorTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SlicesDatabaseAccessorTest.java
@@ -89,8 +89,9 @@
     @Test
     public void testGetSliceFromUri_validUri_validSliceReturned() {
         String key = "key";
+        String path = "intent/" + key;
         insertSpecialCase(key);
-        Uri uri = SliceBuilderUtils.getUri(key, false);
+        Uri uri = SliceBuilderUtils.getUri(path, false);
 
         SliceData data = mAccessor.getSliceDataFromUri(uri);
 
@@ -106,8 +107,7 @@
 
     @Test(expected = IllegalStateException.class)
     public void testGetSliceFromUri_invalidUri_errorThrown() {
-        Uri uri = SliceBuilderUtils.getUri("durr", false);
-
+        Uri uri = SliceBuilderUtils.getUri("intent/durr", false);
         mAccessor.getSliceDataFromUri(uri);
     }
 
diff --git a/tests/robotests/src/com/android/settings/slices/SlicesDatabaseHelperTest.java b/tests/robotests/src/com/android/settings/slices/SlicesDatabaseHelperTest.java
index 7d1b401..98ab2a1 100644
--- a/tests/robotests/src/com/android/settings/slices/SlicesDatabaseHelperTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SlicesDatabaseHelperTest.java
@@ -68,7 +68,9 @@
                 IndexColumns.SCREENTITLE,
                 IndexColumns.ICON_RESOURCE,
                 IndexColumns.FRAGMENT,
-                IndexColumns.CONTROLLER
+                IndexColumns.CONTROLLER,
+                IndexColumns.PLATFORM_SLICE,
+                IndexColumns.SLICE_TYPE,
         };
 
         assertThat(columnNames).isEqualTo(expectedNames);
diff --git a/tests/robotests/src/com/android/settings/slices/SlicesIndexerTest.java b/tests/robotests/src/com/android/settings/slices/SlicesIndexerTest.java
index ca198cb..2af9c79 100644
--- a/tests/robotests/src/com/android/settings/slices/SlicesIndexerTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SlicesIndexerTest.java
@@ -50,6 +50,8 @@
     private final int ICON = 1234; // I declare a thumb war
     private final Uri URI = Uri.parse("content://com.android.settings.slices/test");
     private final String PREF_CONTROLLER = "com.android.settings.slices.tester";
+    private final boolean PLATFORM_DEFINED = true;
+    private final int SLICE_TYPE = SliceData.SliceType.SLIDER;
 
     private Context mContext;
 
@@ -109,10 +111,22 @@
 
         cursor.moveToFirst();
         for (int i = 0; i < sliceData.size(); i++) {
-            assertThat(cursor.getString(cursor.getColumnIndex(IndexColumns.KEY)))
-                .isEqualTo(KEYS[i]);
-            assertThat(cursor.getString(cursor.getColumnIndex(IndexColumns.TITLE)))
-                .isEqualTo(TITLES[i]);
+            assertThat(cursor.getString(cursor.getColumnIndex(IndexColumns.KEY))).isEqualTo(
+                    KEYS[i]);
+            assertThat(cursor.getString(cursor.getColumnIndex(IndexColumns.TITLE))).isEqualTo(
+                    TITLES[i]);
+            assertThat(cursor.getString(cursor.getColumnIndex(IndexColumns.FRAGMENT))).isEqualTo(
+                    FRAGMENT_NAME);
+            assertThat(cursor.getString(cursor.getColumnIndex(IndexColumns.SCREENTITLE))).isEqualTo(
+                    SCREEN_TITLE);
+            assertThat(cursor.getInt(cursor.getColumnIndex(IndexColumns.ICON_RESOURCE))).isEqualTo(
+                    ICON);
+            assertThat(cursor.getString(cursor.getColumnIndex(IndexColumns.CONTROLLER))).isEqualTo(
+                    PREF_CONTROLLER);
+            assertThat(cursor.getInt(cursor.getColumnIndex(IndexColumns.PLATFORM_SLICE))).isEqualTo(
+                    1 /* true */);
+            assertThat(cursor.getInt(cursor.getColumnIndex(IndexColumns.SLICE_TYPE))).isEqualTo(
+                    SLICE_TYPE);
             cursor.moveToNext();
         }
     }
@@ -126,15 +140,17 @@
     }
 
     private List<SliceData> getDummyIndexableData() {
-        final SliceData.Builder builder = new SliceData.Builder()
-            .setSummary(SUMMARY)
-            .setScreenTitle(SCREEN_TITLE)
-            .setFragmentName(FRAGMENT_NAME)
-            .setIcon(ICON)
-            .setUri(URI)
-            .setPreferenceControllerClassName(PREF_CONTROLLER);
-
         final List<SliceData> sliceData = new ArrayList<>();
+        final SliceData.Builder builder = new SliceData.Builder()
+                .setSummary(SUMMARY)
+                .setScreenTitle(SCREEN_TITLE)
+                .setFragmentName(FRAGMENT_NAME)
+                .setIcon(ICON)
+                .setUri(URI)
+                .setPreferenceControllerClassName(PREF_CONTROLLER)
+                .setPlatformDefined(PLATFORM_DEFINED)
+                .setSliceType(SLICE_TYPE);
+
         for (int i = 0; i < KEYS.length; i++) {
             builder.setKey(KEYS[i]).setTitle(TITLES[i]);
             sliceData.add(builder.build());