diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index dbe231b5255..f1bb5954ef5 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -3218,7 +3218,7 @@
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index d37091c5948..d0ddab6ffe2 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -96,8 +96,12 @@
+
+
+
+
diff --git a/res/xml/connected_devices_advanced.xml b/res/xml/connected_devices_advanced.xml
index 36eab229754..dda5655f083 100644
--- a/res/xml/connected_devices_advanced.xml
+++ b/res/xml/connected_devices_advanced.xml
@@ -26,7 +26,8 @@
android:icon="@drawable/ic_settings_bluetooth"
android:summary="@string/bluetooth_pref_summary"
android:order="-7"
- settings:controller="com.android.settings.bluetooth.BluetoothSwitchPreferenceController"/>
+ settings:controller="com.android.settings.bluetooth.BluetoothSwitchPreferenceController"
+ settings:platform_slice="true"/>
outerDepth));
parser.close();
@@ -205,12 +239,16 @@ public class PreferenceXmlParserUtils {
* Returns the fragment name if this preference launches a child fragment.
*/
public static String getDataChildFragment(Context context, AttributeSet attrs) {
- return getData(context, attrs, R.styleable.Preference,
+ return getStringData(context, attrs, R.styleable.Preference,
R.styleable.Preference_android_fragment);
}
+ /**
+ * Call {@link #extractMetadata(Context, int, int)} with a {@link MetadataFlag} instead.
+ */
+ @Deprecated
@Nullable
- private static String getData(Context context, AttributeSet set, int[] attrs, int resId) {
+ private static String getStringData(Context context, AttributeSet set, int[] attrs, int resId) {
final TypedArray ta = context.obtainStyledAttributes(set, attrs);
String data = ta.getString(resId);
ta.recycle();
@@ -243,4 +281,28 @@ public class PreferenceXmlParserUtils {
}
return result.toString();
}
+
+ private static String getKey(TypedArray styledAttributes) {
+ return styledAttributes.getString(com.android.internal.R.styleable.Preference_key);
+ }
+
+ private static String getTitle(TypedArray styledAttributes) {
+ return styledAttributes.getString(com.android.internal.R.styleable.Preference_title);
+ }
+
+ private static String getSummary(TypedArray styledAttributes) {
+ return styledAttributes.getString(com.android.internal.R.styleable.Preference_summary);
+ }
+
+ private static String getController(TypedArray styledAttributes) {
+ return styledAttributes.getString(R.styleable.Preference_controller);
+ }
+
+ private static int getIcon(TypedArray styledAttributes) {
+ return styledAttributes.getResourceId(com.android.internal.R.styleable.Icon_icon, 0);
+ }
+
+ private static boolean getPlatformSlice(TypedArray styledAttributes) {
+ return styledAttributes.getBoolean(R.styleable.Preference_platform_slice, false /* def */);
+ }
}
diff --git a/src/com/android/settings/slices/SettingsSliceProvider.java b/src/com/android/settings/slices/SettingsSliceProvider.java
index d8ba991a145..68c9731d8cb 100644
--- a/src/com/android/settings/slices/SettingsSliceProvider.java
+++ b/src/com/android/settings/slices/SettingsSliceProvider.java
@@ -24,6 +24,7 @@ import android.content.Intent;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.net.wifi.WifiManager;
+import android.provider.SettingsSlicesContract;
import android.support.annotation.VisibleForTesting;
import android.util.Log;
@@ -63,6 +64,10 @@ public class SettingsSliceProvider extends SliceProvider {
private static final String TAG = "SettingsSliceProvider";
+ /**
+ * Authority for Settings slices not officially supported by the platform, but extensible for
+ * OEMs.
+ */
public static final String SLICE_AUTHORITY = "com.android.settings.slices";
public static final String PATH_WIFI = "wifi";
@@ -82,13 +87,6 @@ public class SettingsSliceProvider extends SliceProvider {
@VisibleForTesting
Map mSliceDataCache;
- public static Uri getUri(String path) {
- return new Uri.Builder()
- .scheme(ContentResolver.SCHEME_CONTENT)
- .authority(SLICE_AUTHORITY)
- .appendPath(path).build();
- }
-
@Override
public boolean onCreateSliceProvider() {
mSlicesDatabaseAccessor = new SlicesDatabaseAccessor(getContext());
@@ -176,7 +174,8 @@ public class SettingsSliceProvider extends SliceProvider {
.setSubtitle(state)
.addEndItem(new SliceAction(getBroadcastIntent(ACTION_WIFI_CHANGED),
null, finalWifiEnabled))
- .setPrimaryAction(new SliceAction(getIntent(Intent.ACTION_MAIN), null, null)))
+ .setPrimaryAction(
+ new SliceAction(getIntent(Intent.ACTION_MAIN), null, null)))
.build();
}
diff --git a/src/com/android/settings/slices/SliceBroadcastReceiver.java b/src/com/android/settings/slices/SliceBroadcastReceiver.java
index a68ed19db1d..4124df7718c 100644
--- a/src/com/android/settings/slices/SliceBroadcastReceiver.java
+++ b/src/com/android/settings/slices/SliceBroadcastReceiver.java
@@ -59,7 +59,8 @@ public class SliceBroadcastReceiver extends BroadcastReceiver {
// Wait a bit for wifi to update (TODO: is there a better way to do this?)
Handler h = new Handler();
h.postDelayed(() -> {
- Uri uri = SettingsSliceProvider.getUri(SettingsSliceProvider.PATH_WIFI);
+ Uri uri = SliceBuilderUtils.getUri(SettingsSliceProvider.PATH_WIFI,
+ false /* isPlatformSlice */);
context.getContentResolver().notifyChange(uri, null);
}, 1000);
break;
diff --git a/src/com/android/settings/slices/SliceBuilderUtils.java b/src/com/android/settings/slices/SliceBuilderUtils.java
index e94ee56ddc6..e90ea8e9f68 100644
--- a/src/com/android/settings/slices/SliceBuilderUtils.java
+++ b/src/com/android/settings/slices/SliceBuilderUtils.java
@@ -19,9 +19,12 @@ package com.android.settings.slices;
import static com.android.settings.slices.SettingsSliceProvider.EXTRA_SLICE_KEY;
import android.app.PendingIntent;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Icon;
+import android.net.Uri;
+import android.provider.SettingsSlicesContract;
import android.text.TextUtils;
import com.android.internal.annotations.VisibleForTesting;
@@ -98,6 +101,17 @@ public class SliceBuilderUtils {
sliceData.getKey());
}
+ public static Uri getUri(String path, boolean isPlatformSlice) {
+ final String authority = isPlatformSlice
+ ? SettingsSlicesContract.AUTHORITY
+ : SettingsSliceProvider.SLICE_AUTHORITY;
+ return new Uri.Builder()
+ .scheme(ContentResolver.SCHEME_CONTENT)
+ .authority(authority)
+ .appendPath(path)
+ .build();
+ }
+
private static BasePreferenceController getPreferenceController(Context context,
String controllerClassName, String controllerKey) {
try {
diff --git a/src/com/android/settings/slices/SliceData.java b/src/com/android/settings/slices/SliceData.java
index a7c9a116dad..c02b1135699 100644
--- a/src/com/android/settings/slices/SliceData.java
+++ b/src/com/android/settings/slices/SliceData.java
@@ -70,6 +70,8 @@ public class SliceData {
@SliceType
private final int mSliceType;
+ private final boolean mIsPlatformDefined;
+
public String getKey() {
return mKey;
}
@@ -106,6 +108,10 @@ public class SliceData {
return mSliceType;
}
+ public boolean isPlatformDefined() {
+ return mIsPlatformDefined;
+ }
+
private SliceData(Builder builder) {
mKey = builder.mKey;
mTitle = builder.mTitle;
@@ -116,6 +122,7 @@ public class SliceData {
mUri = builder.mUri;
mPreferenceController = builder.mPrefControllerClassName;
mSliceType = builder.mSliceType;
+ mIsPlatformDefined = builder.mIsPlatformDefined;
}
@Override
@@ -151,6 +158,8 @@ public class SliceData {
private int mSliceType;
+ private boolean mIsPlatformDefined;
+
public Builder setKey(String key) {
mKey = key;
return this;
@@ -196,6 +205,11 @@ public class SliceData {
return this;
}
+ public Builder setPlatformDefined(boolean isPlatformDefined) {
+ mIsPlatformDefined = isPlatformDefined;
+ return this;
+ }
+
public SliceData build() {
if (TextUtils.isEmpty(mKey)) {
throw new IllegalStateException("Key cannot be empty");
diff --git a/src/com/android/settings/slices/SliceDataConverter.java b/src/com/android/settings/slices/SliceDataConverter.java
index e7b53d03940..7cf1994f9ed 100644
--- a/src/com/android/settings/slices/SliceDataConverter.java
+++ b/src/com/android/settings/slices/SliceDataConverter.java
@@ -19,6 +19,7 @@ package com.android.settings.slices;
import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_CONTROLLER;
import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_ICON;
import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_KEY;
+import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_PLATFORM_SLICE_FLAG;
import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_SUMMARY;
import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_TITLE;
@@ -164,7 +165,8 @@ class SliceDataConverter {
| MetadataFlag.FLAG_NEED_PREF_TYPE
| MetadataFlag.FLAG_NEED_PREF_TITLE
| MetadataFlag.FLAG_NEED_PREF_ICON
- | MetadataFlag.FLAG_NEED_PREF_SUMMARY);
+ | MetadataFlag.FLAG_NEED_PREF_SUMMARY
+ | MetadataFlag.FLAG_NEED_PLATFORM_SLICE_FLAG);
for (Bundle bundle : metadata) {
// TODO (b/67996923) Non-controller Slices should become intent-only slices.
@@ -179,6 +181,7 @@ class SliceDataConverter {
final int iconResId = bundle.getInt(METADATA_ICON);
final int sliceType = SliceBuilderUtils.getSliceType(mContext, controllerClassName,
key);
+ final boolean isPlatformSlice = bundle.getBoolean(METADATA_PLATFORM_SLICE_FLAG);
final SliceData xmlSlice = new SliceData.Builder()
.setKey(key)
@@ -189,6 +192,7 @@ class SliceDataConverter {
.setPreferenceControllerClassName(controllerClassName)
.setFragmentName(fragmentName)
.setSliceType(sliceType)
+ .setPlatformDefined(isPlatformSlice)
.build();
xmlSliceData.add(xmlSlice);
diff --git a/tests/robotests/res/xml-mcc999/location_settings.xml b/tests/robotests/res/xml-mcc999/location_settings.xml
index 5619c774a6d..08cd8ad65d2 100644
--- a/tests/robotests/res/xml-mcc999/location_settings.xml
+++ b/tests/robotests/res/xml-mcc999/location_settings.xml
@@ -25,6 +25,7 @@
android:title="title"
android:icon="@drawable/ic_android"
android:summary="summary"
- settings:controller="com.android.settings.slices.FakePreferenceController"/>
+ settings:controller="com.android.settings.slices.FakePreferenceController"
+ settings:platform_slice="true"/>
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java b/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java
index 50f47ff7801..9edae7e39cb 100644
--- a/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SettingsSliceProviderTest.java
@@ -18,8 +18,7 @@
package com.android.settings.slices;
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
+
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
@@ -28,6 +27,7 @@ import android.content.ContentValues;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
+import android.provider.SettingsSlicesContract;
import com.android.settings.testutils.DatabaseTestUtils;
import com.android.settings.testutils.FakeToggleController;
@@ -50,6 +50,8 @@ import java.util.HashMap;
public class SettingsSliceProviderTest {
private final String KEY = "KEY";
+ private final String INTENT_PATH = SettingsSlicesContract.PATH_SETTING_INTENT + "/" + KEY;
+ private final String ACTION_PATH = SettingsSlicesContract.PATH_SETTING_ACTION + "/" + KEY;
private final String TITLE = "title";
private final String SUMMARY = "summary";
private final String SCREEN_TITLE = "screen title";
@@ -67,6 +69,8 @@ public class SettingsSliceProviderTest {
mProvider = spy(new SettingsSliceProvider());
mProvider.mSliceDataCache = new HashMap<>();
mProvider.mSlicesDatabaseAccessor = new SlicesDatabaseAccessor(mContext);
+ when(mProvider.getContext()).thenReturn(mContext);
+
mDb = SlicesDatabaseHelper.getInstance(mContext).getWritableDatabase();
SlicesDatabaseHelper.getInstance(mContext).setIndexedState();
}
@@ -78,34 +82,18 @@ public class SettingsSliceProviderTest {
@Test
public void testInitialSliceReturned_emptySlice() {
- insertSpecialCase(KEY);
- ContentResolver mockResolver = mock(ContentResolver.class);
- doReturn(mockResolver).when(mContext).getContentResolver();
- when(mProvider.getContext()).thenReturn(mContext);
-
- Uri uri = SettingsSliceProvider.getUri(KEY);
+ insertSpecialCase(INTENT_PATH);
+ Uri uri = SliceBuilderUtils.getUri(INTENT_PATH, false);
Slice slice = mProvider.onBindSlice(uri);
assertThat(slice.getUri()).isEqualTo(uri);
assertThat(slice.getItems()).isEmpty();
}
- @Test
- public void testUriBuilder_returnsValidSliceUri() {
- Uri uri = SettingsSliceProvider.getUri(KEY);
-
- assertThat(uri.getScheme()).isEqualTo(ContentResolver.SCHEME_CONTENT);
- assertThat(uri.getAuthority()).isEqualTo(SettingsSliceProvider.SLICE_AUTHORITY);
- assertThat(uri.getLastPathSegment()).isEqualTo(KEY);
- }
-
@Test
public void testLoadSlice_returnsSliceFromAccessor() {
- ContentResolver mockResolver = mock(ContentResolver.class);
- doReturn(mockResolver).when(mContext).getContentResolver();
- when(mProvider.getContext()).thenReturn(mContext);
insertSpecialCase(KEY);
- Uri uri = SettingsSliceProvider.getUri(KEY);
+ Uri uri = SliceBuilderUtils.getUri(KEY, false);
mProvider.loadSlice(uri);
SliceData data = mProvider.mSliceDataCache.get(uri);
@@ -116,7 +104,6 @@ public class SettingsSliceProviderTest {
@Test
public void testLoadSlice_cachedEntryRemovedOnBuild() {
- when(mProvider.getContext()).thenReturn(mContext);
SliceData data = getDummyData();
mProvider.mSliceDataCache.put(data.getUri(), data);
mProvider.onBindSlice(data.getUri());
diff --git a/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java b/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java
index 5a2271aadd2..0fcce5fb19a 100644
--- a/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java
@@ -20,8 +20,10 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
+import android.content.ContentResolver;
import android.content.Context;
import android.net.Uri;
+import android.provider.SettingsSlicesContract;
import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
@@ -48,6 +50,9 @@ public class SliceBuilderUtilsTest {
private final Class PREF_CONTROLLER = FakeToggleController.class;
private final Class PREF_CONTROLLER2 = FakeContextOnlyPreferenceController.class;
+ private final String INTENT_PATH = SettingsSlicesContract.PATH_SETTING_INTENT + "/" + KEY;
+ private final String ACTION_PATH = SettingsSlicesContract.PATH_SETTING_ACTION + "/" + KEY;
+
private Context mContext;
@Before
@@ -62,6 +67,58 @@ public class SliceBuilderUtilsTest {
assertThat(slice).isNotNull(); // TODO improve test for Slice content
}
+ @Test
+ public void testUriBuilder_oemAuthority_intentPath_returnsValidSliceUri() {
+ Uri expectedUri = new Uri.Builder()
+ .scheme(ContentResolver.SCHEME_CONTENT)
+ .authority(SettingsSliceProvider.SLICE_AUTHORITY)
+ .appendPath(INTENT_PATH)
+ .build();
+
+ Uri actualUri = SliceBuilderUtils.getUri(INTENT_PATH, false);
+
+ assertThat(actualUri).isEqualTo(expectedUri);
+ }
+
+ @Test
+ public void testUriBuilder_oemAuthority_actionPath_returnsValidSliceUri() {
+ Uri expectedUri = new Uri.Builder()
+ .scheme(ContentResolver.SCHEME_CONTENT)
+ .authority(SettingsSliceProvider.SLICE_AUTHORITY)
+ .appendPath(ACTION_PATH)
+ .build();
+
+ Uri actualUri = SliceBuilderUtils.getUri(ACTION_PATH, false);
+
+ assertThat(actualUri).isEqualTo(expectedUri);
+ }
+
+ @Test
+ public void testUriBuilder_platformAuthority_intentPath_returnsValidSliceUri() {
+ Uri expectedUri = new Uri.Builder()
+ .scheme(ContentResolver.SCHEME_CONTENT)
+ .authority(SettingsSlicesContract.AUTHORITY)
+ .appendPath(ACTION_PATH)
+ .build();
+
+ Uri actualUri = SliceBuilderUtils.getUri(ACTION_PATH, true);
+
+ assertThat(actualUri).isEqualTo(expectedUri);
+ }
+
+ @Test
+ public void testUriBuilder_platformAuthority_actionPath_returnsValidSliceUri() {
+ Uri expectedUri = new Uri.Builder()
+ .scheme(ContentResolver.SCHEME_CONTENT)
+ .authority(SettingsSlicesContract.AUTHORITY)
+ .appendPath(ACTION_PATH)
+ .build();
+
+ Uri actualUri = SliceBuilderUtils.getUri(ACTION_PATH, true);
+
+ assertThat(actualUri).isEqualTo(expectedUri);
+ }
+
@Test
public void testGetPreferenceController_buildsMatchingController() {
BasePreferenceController controller =
diff --git a/tests/robotests/src/com/android/settings/slices/SliceDataConverterTest.java b/tests/robotests/src/com/android/settings/slices/SliceDataConverterTest.java
index 4d6c08dda8b..36c27548c13 100644
--- a/tests/robotests/src/com/android/settings/slices/SliceDataConverterTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SliceDataConverterTest.java
@@ -81,6 +81,7 @@ public class SliceDataConverterTest {
assertThat(fakeSlice.getUri()).isNull();
assertThat(fakeSlice.getFragmentClassName()).isEqualTo(fakeFragmentClassName);
assertThat(fakeSlice.getPreferenceController()).isEqualTo(fakeControllerName);
- assertThat(fakeSlice.getSliceType()).isEqualTo(SliceData.SliceType.SLIDER);
+ assertThat(fakeSlice.getSliceType()).isEqualTo(SliceData.SliceType.SLIDER); // from XML
+ assertThat(fakeSlice.isPlatformDefined()).isTrue(); // from XML
}
}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/slices/SliceDataTest.java b/tests/robotests/src/com/android/settings/slices/SliceDataTest.java
index 7cd19b5bcf7..c2ab0afb183 100644
--- a/tests/robotests/src/com/android/settings/slices/SliceDataTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SliceDataTest.java
@@ -37,6 +37,7 @@ public class SliceDataTest {
private final Uri URI = Uri.parse("content://com.android.settings.slices/test");
private final String PREF_CONTROLLER = "com.android.settings.slices.tester";
private final int SLICE_TYPE = SliceData.SliceType.SWITCH;
+ private final boolean IS_PLATFORM_DEFINED = true;
@Test
public void testBuilder_buildsMatchingObject() {
@@ -49,7 +50,8 @@ public class SliceDataTest {
.setFragmentName(FRAGMENT_NAME)
.setUri(URI)
.setPreferenceControllerClassName(PREF_CONTROLLER)
- .setSliceType(SLICE_TYPE);
+ .setSliceType(SLICE_TYPE)
+ .setPlatformDefined(IS_PLATFORM_DEFINED);
SliceData data = builder.build();
@@ -62,6 +64,7 @@ public class SliceDataTest {
assertThat(data.getUri()).isEqualTo(URI);
assertThat(data.getPreferenceController()).isEqualTo(PREF_CONTROLLER);
assertThat(data.getSliceType()).isEqualTo(SLICE_TYPE);
+ assertThat(data.isPlatformDefined()).isEqualTo(IS_PLATFORM_DEFINED);
}
@Test(expected = IllegalStateException.class)
diff --git a/tests/robotests/src/com/android/settings/slices/SlicesDatabaseAccessorTest.java b/tests/robotests/src/com/android/settings/slices/SlicesDatabaseAccessorTest.java
index 8989de9ef7f..331058c96c5 100644
--- a/tests/robotests/src/com/android/settings/slices/SlicesDatabaseAccessorTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SlicesDatabaseAccessorTest.java
@@ -90,7 +90,7 @@ public class SlicesDatabaseAccessorTest {
public void testGetSliceFromUri_validUri_validSliceReturned() {
String key = "key";
insertSpecialCase(key);
- Uri uri = SettingsSliceProvider.getUri(key);
+ Uri uri = SliceBuilderUtils.getUri(key, false);
SliceData data = mAccessor.getSliceDataFromUri(uri);
@@ -106,7 +106,7 @@ public class SlicesDatabaseAccessorTest {
@Test(expected = IllegalStateException.class)
public void testGetSliceFromUri_invalidUri_errorThrown() {
- Uri uri = SettingsSliceProvider.getUri("durr");
+ Uri uri = SliceBuilderUtils.getUri("durr", false);
mAccessor.getSliceDataFromUri(uri);
}