Merge "Add bluetooth as a supported Slice"
diff --git a/res/xml/connected_devices_advanced.xml b/res/xml/connected_devices_advanced.xml
index 078d7dd..8ca6b81 100644
--- a/res/xml/connected_devices_advanced.xml
+++ b/res/xml/connected_devices_advanced.xml
@@ -16,6 +16,7 @@
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:settings="http://schemas.android.com/apk/res-auto"
android:key="connected_devices_screen"
android:title="@string/connected_device_connections_title">
@@ -24,6 +25,7 @@
android:title="@string/bluetooth_settings_title"
android:icon="@drawable/ic_settings_bluetooth"
android:summary="@string/bluetooth_pref_summary"
+ settings:controller="com.android.settings.bluetooth.BluetoothSwitchPreferenceController"
android:order="-7"/>
<SwitchPreference
diff --git a/src/com/android/settings/slices/SettingsSliceProvider.java b/src/com/android/settings/slices/SettingsSliceProvider.java
index e068b2f..433bdf3 100644
--- a/src/com/android/settings/slices/SettingsSliceProvider.java
+++ b/src/com/android/settings/slices/SettingsSliceProvider.java
@@ -30,7 +30,6 @@
import com.android.settings.R;
import com.android.settingslib.utils.ThreadUtils;
-import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;
diff --git a/src/com/android/settings/slices/SliceBuilderUtils.java b/src/com/android/settings/slices/SliceBuilderUtils.java
index e9152ba..11ff1c1 100644
--- a/src/com/android/settings/slices/SliceBuilderUtils.java
+++ b/src/com/android/settings/slices/SliceBuilderUtils.java
@@ -23,6 +23,7 @@
import android.content.Intent;
import android.graphics.drawable.Icon;
import android.text.TextUtils;
+import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.R;
@@ -85,17 +86,46 @@
*/
public static BasePreferenceController getPreferenceController(Context context,
SliceData sliceData) {
- // TODO check for context-only controller first.
+ try {
+ return getController(context, sliceData, true /* isContextOnly */);
+ } catch (IllegalStateException e) {
+ // Do nothing
+ Log.d(TAG, "Could not find Context-only controller for preference controller: "
+ + sliceData.getKey());
+ }
+
+ return getController(context, sliceData, false /* isContextOnly */);
+ }
+
+ /**
+ * Attempts to build a {@link BasePreferenceController} from {@param SliceData}.
+ *
+ * @param sliceData Backing data for the Slice.
+ * @param contextOnlyCtor {@code true} when the constructor for the
+ * {@link BasePreferenceController}
+ * only takes a {@link Context}. Else the constructor will be ({@link
+ * Context}, {@code String}.
+ */
+ private static BasePreferenceController getController(Context context, SliceData sliceData,
+ boolean contextOnlyCtor) {
try {
Class<?> clazz = Class.forName(sliceData.getPreferenceController());
- Constructor<?> preferenceConstructor = clazz.getConstructor(Context.class,
- String.class);
- return (BasePreferenceController) preferenceConstructor.newInstance(
- new Object[]{context, sliceData.getKey()});
+ Constructor<?> preferenceConstructor;
+ Object[] params;
+
+ if (contextOnlyCtor) {
+ preferenceConstructor = clazz.getConstructor(Context.class);
+ params = new Object[]{context};
+ } else {
+ preferenceConstructor = clazz.getConstructor(Context.class, String.class);
+ params = new Object[]{context, sliceData.getKey()};
+ }
+
+ return (BasePreferenceController) preferenceConstructor.newInstance(params);
} catch (ClassNotFoundException | NoSuchMethodException | InstantiationException |
IllegalArgumentException | InvocationTargetException | IllegalAccessException e) {
throw new IllegalStateException(
- "Invalid preference controller: " + sliceData.getPreferenceController());
+ "Invalid preference controller: " + sliceData.getPreferenceController(), e);
}
}
diff --git a/tests/robotests/src/com/android/settings/core/XmlControllerAttributeTest.java b/tests/robotests/src/com/android/settings/core/XmlControllerAttributeTest.java
index 8ded9d6..e6ca59b 100644
--- a/tests/robotests/src/com/android/settings/core/XmlControllerAttributeTest.java
+++ b/tests/robotests/src/com/android/settings/core/XmlControllerAttributeTest.java
@@ -80,11 +80,6 @@
private static final String BAD_CLASSNAME_ERROR =
"The following controllers set in the XML did not have valid class names:\n";
- private static final String BAD_CONSTRUCTOR_ERROR =
- "The constructor provided by the following classes were insufficient to instantiate "
- + "the object. It could be due to being an interface, abstract, or an "
- + "IllegalAccessException. Please fix the following classes:\n";
-
Context mContext;
SearchFeatureProvider mSearchProvider;
private FakeFeatureFactory mFakeFeatureFactory;
@@ -112,7 +107,6 @@
Set<String> invalidConstructors = new HashSet<>();
Set<String> invalidClassHierarchy = new HashSet<>();
Set<String> badClassNameControllers = new HashSet<>();
- Set<String> badConstructorControllers = new HashSet<>();
for (int resId : xmlSet) {
xmlControllers.addAll(getXmlControllers(resId));
@@ -133,13 +127,7 @@
continue;
}
- Object controller = getObjectFromConstructor(constructor);
- if (controller == null) {
- badConstructorControllers.add(controllerClassName);
- continue;
- }
-
- if (!(controller instanceof BasePreferenceController)) {
+ if (!isBasePreferenceController(clazz)) {
invalidClassHierarchy.add(controllerClassName);
}
}
@@ -150,13 +138,10 @@
invalidClassHierarchy);
final String badClassNameError = buildErrorMessage(BAD_CLASSNAME_ERROR,
badClassNameControllers);
- final String badConstructorError = buildErrorMessage(BAD_CONSTRUCTOR_ERROR,
- badConstructorControllers);
assertWithMessage(invalidConstructorError).that(invalidConstructors).isEmpty();
assertWithMessage(invalidClassHierarchyError).that(invalidClassHierarchy).isEmpty();
assertWithMessage(badClassNameError).that(badClassNameControllers).isEmpty();
- assertWithMessage(badConstructorError).that(badConstructorControllers).isEmpty();
}
private Set<Integer> getIndexableXml() {
@@ -260,25 +245,16 @@
return constructor;
}
- private Object getObjectFromConstructor(Constructor<?> constructor) {
- Object controller = null;
-
- try {
- controller = constructor.newInstance(mContext);
- } catch (InstantiationException | IllegalAccessException | InvocationTargetException |
- IllegalArgumentException e) {
+ /**
+ * Make sure that {@link BasePreferenceController} is in the class hierarchy.
+ */
+ private boolean isBasePreferenceController(Class<?> clazz) {
+ while (clazz != null) {
+ clazz = clazz.getSuperclass();
+ if (BasePreferenceController.class.equals(clazz)) {
+ return true;
+ }
}
-
- if (controller != null) {
- return controller;
- }
-
- try {
- controller = constructor.newInstance(mContext, "key");
- } catch (InstantiationException | IllegalAccessException | InvocationTargetException |
- IllegalArgumentException e) {
- }
-
- return controller;
+ return false;
}
-}
+}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/slices/FakeContextOnlyPreferenceController.java b/tests/robotests/src/com/android/settings/slices/FakeContextOnlyPreferenceController.java
new file mode 100644
index 0000000..214607b
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/slices/FakeContextOnlyPreferenceController.java
@@ -0,0 +1,19 @@
+package com.android.settings.slices;
+
+import android.content.Context;
+
+import com.android.settings.core.BasePreferenceController;
+
+public class FakeContextOnlyPreferenceController extends BasePreferenceController {
+
+ public static final String KEY = "fakeController2";
+
+ public FakeContextOnlyPreferenceController(Context context) {
+ super(context, KEY);
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return AVAILABLE;
+ }
+}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java b/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java
index 10e4b76..0923571 100644
--- a/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java
@@ -50,8 +50,8 @@
private final String FRAGMENT_NAME = "fragment name";
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 = FakeToggleController.class.getName();
- ;
+ private final Class PREF_CONTROLLER = FakeToggleController.class;
+ private final Class PREF_CONTROLLER2 = FakeContextOnlyPreferenceController.class;
private Context mContext;
@@ -76,6 +76,14 @@
}
@Test
+ public void testGetPreferenceController_contextOnly_buildsMatchingController() {
+ BasePreferenceController controller = SliceBuilderUtils.getPreferenceController(mContext,
+ getDummyData(PREF_CONTROLLER2));
+
+ assertThat(controller).isInstanceOf(FakeContextOnlyPreferenceController.class);
+ }
+
+ @Test
public void testDynamicSummary_returnsSliceSummary() {
SliceData data = getDummyData();
FakePreferenceController controller = new FakePreferenceController(mContext, KEY);
@@ -87,7 +95,7 @@
@Test
public void testDynamicSummary_returnsFragmentSummary() {
- SliceData data = getDummyData(null);
+ SliceData data = getDummyData((String) null);
FakePreferenceController controller = spy(new FakePreferenceController(mContext, KEY));
String controllerSummary = "new_Summary";
doReturn(controllerSummary).when(controller).getSummary();
@@ -99,7 +107,7 @@
@Test
public void testDynamicSummary_returnsSliceScreenTitle() {
- SliceData data = getDummyData(null);
+ SliceData data = getDummyData((String) null);
FakePreferenceController controller = new FakePreferenceController(mContext, KEY);
String summary = SliceBuilderUtils.getSubtitleText(mContext, controller, data);
@@ -129,10 +137,18 @@
}
private SliceData getDummyData() {
- return getDummyData(SUMMARY);
+ return getDummyData(PREF_CONTROLLER, SUMMARY);
}
private SliceData getDummyData(String summary) {
+ return getDummyData(PREF_CONTROLLER, summary);
+ }
+
+ private SliceData getDummyData(Class prefController) {
+ return getDummyData(prefController, SUMMARY);
+ }
+
+ private SliceData getDummyData(Class prefController, String summary) {
return new SliceData.Builder()
.setKey(KEY)
.setTitle(TITLE)
@@ -141,7 +157,7 @@
.setIcon(ICON)
.setFragmentName(FRAGMENT_NAME)
.setUri(URI)
- .setPreferenceControllerClassName(PREF_CONTROLLER)
+ .setPreferenceControllerClassName(prefController.getName())
.build();
}
}