Merge "Add bluetooth as a supported Slice"

This commit is contained in:
TreeHugger Robot
2018-01-24 18:39:18 +00:00
committed by Android (Google) Code Review
6 changed files with 91 additions and 49 deletions

View File

@@ -16,6 +16,7 @@
<PreferenceScreen <PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:key="connected_devices_screen" android:key="connected_devices_screen"
android:title="@string/connected_device_connections_title"> android:title="@string/connected_device_connections_title">
@@ -24,6 +25,7 @@
android:title="@string/bluetooth_settings_title" android:title="@string/bluetooth_settings_title"
android:icon="@drawable/ic_settings_bluetooth" android:icon="@drawable/ic_settings_bluetooth"
android:summary="@string/bluetooth_pref_summary" android:summary="@string/bluetooth_pref_summary"
settings:controller="com.android.settings.bluetooth.BluetoothSwitchPreferenceController"
android:order="-7"/> android:order="-7"/>
<SwitchPreference <SwitchPreference

View File

@@ -30,7 +30,6 @@ import android.util.Log;
import com.android.settings.R; import com.android.settings.R;
import com.android.settingslib.utils.ThreadUtils; import com.android.settingslib.utils.ThreadUtils;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.WeakHashMap; import java.util.WeakHashMap;

View File

@@ -23,6 +23,7 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.graphics.drawable.Icon; import android.graphics.drawable.Icon;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.R; import com.android.settings.R;
@@ -85,17 +86,46 @@ public class SliceBuilderUtils {
*/ */
public static BasePreferenceController getPreferenceController(Context context, public static BasePreferenceController getPreferenceController(Context context,
SliceData sliceData) { 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 { try {
Class<?> clazz = Class.forName(sliceData.getPreferenceController()); Class<?> clazz = Class.forName(sliceData.getPreferenceController());
Constructor<?> preferenceConstructor = clazz.getConstructor(Context.class, Constructor<?> preferenceConstructor;
String.class); Object[] params;
return (BasePreferenceController) preferenceConstructor.newInstance(
new Object[]{context, sliceData.getKey()}); 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 | } catch (ClassNotFoundException | NoSuchMethodException | InstantiationException |
IllegalArgumentException | InvocationTargetException | IllegalAccessException e) { IllegalArgumentException | InvocationTargetException | IllegalAccessException e) {
throw new IllegalStateException( throw new IllegalStateException(
"Invalid preference controller: " + sliceData.getPreferenceController()); "Invalid preference controller: " + sliceData.getPreferenceController(), e);
} }
} }

View File

@@ -80,11 +80,6 @@ public class XmlControllerAttributeTest {
private static final String BAD_CLASSNAME_ERROR = private static final String BAD_CLASSNAME_ERROR =
"The following controllers set in the XML did not have valid class names:\n"; "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; Context mContext;
SearchFeatureProvider mSearchProvider; SearchFeatureProvider mSearchProvider;
private FakeFeatureFactory mFakeFeatureFactory; private FakeFeatureFactory mFakeFeatureFactory;
@@ -112,7 +107,6 @@ public class XmlControllerAttributeTest {
Set<String> invalidConstructors = new HashSet<>(); Set<String> invalidConstructors = new HashSet<>();
Set<String> invalidClassHierarchy = new HashSet<>(); Set<String> invalidClassHierarchy = new HashSet<>();
Set<String> badClassNameControllers = new HashSet<>(); Set<String> badClassNameControllers = new HashSet<>();
Set<String> badConstructorControllers = new HashSet<>();
for (int resId : xmlSet) { for (int resId : xmlSet) {
xmlControllers.addAll(getXmlControllers(resId)); xmlControllers.addAll(getXmlControllers(resId));
@@ -133,13 +127,7 @@ public class XmlControllerAttributeTest {
continue; continue;
} }
Object controller = getObjectFromConstructor(constructor); if (!isBasePreferenceController(clazz)) {
if (controller == null) {
badConstructorControllers.add(controllerClassName);
continue;
}
if (!(controller instanceof BasePreferenceController)) {
invalidClassHierarchy.add(controllerClassName); invalidClassHierarchy.add(controllerClassName);
} }
} }
@@ -150,13 +138,10 @@ public class XmlControllerAttributeTest {
invalidClassHierarchy); invalidClassHierarchy);
final String badClassNameError = buildErrorMessage(BAD_CLASSNAME_ERROR, final String badClassNameError = buildErrorMessage(BAD_CLASSNAME_ERROR,
badClassNameControllers); badClassNameControllers);
final String badConstructorError = buildErrorMessage(BAD_CONSTRUCTOR_ERROR,
badConstructorControllers);
assertWithMessage(invalidConstructorError).that(invalidConstructors).isEmpty(); assertWithMessage(invalidConstructorError).that(invalidConstructors).isEmpty();
assertWithMessage(invalidClassHierarchyError).that(invalidClassHierarchy).isEmpty(); assertWithMessage(invalidClassHierarchyError).that(invalidClassHierarchy).isEmpty();
assertWithMessage(badClassNameError).that(badClassNameControllers).isEmpty(); assertWithMessage(badClassNameError).that(badClassNameControllers).isEmpty();
assertWithMessage(badConstructorError).that(badConstructorControllers).isEmpty();
} }
private Set<Integer> getIndexableXml() { private Set<Integer> getIndexableXml() {
@@ -260,25 +245,16 @@ public class XmlControllerAttributeTest {
return constructor; return constructor;
} }
private Object getObjectFromConstructor(Constructor<?> constructor) { /**
Object controller = null; * Make sure that {@link BasePreferenceController} is in the class hierarchy.
*/
try { private boolean isBasePreferenceController(Class<?> clazz) {
controller = constructor.newInstance(mContext); while (clazz != null) {
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | clazz = clazz.getSuperclass();
IllegalArgumentException e) { if (BasePreferenceController.class.equals(clazz)) {
return true;
}
} }
return false;
if (controller != null) {
return controller;
}
try {
controller = constructor.newInstance(mContext, "key");
} catch (InstantiationException | IllegalAccessException | InvocationTargetException |
IllegalArgumentException e) {
}
return controller;
} }
} }

View File

@@ -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;
}
}

View File

@@ -50,8 +50,8 @@ public class SliceBuilderUtilsTest {
private final String FRAGMENT_NAME = "fragment name"; private final String FRAGMENT_NAME = "fragment name";
private final int ICON = 1234; // I declare a thumb war private final int ICON = 1234; // I declare a thumb war
private final Uri URI = Uri.parse("content://com.android.settings.slices/test"); 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; private Context mContext;
@@ -75,6 +75,14 @@ public class SliceBuilderUtilsTest {
assertThat(controller).isInstanceOf(FakeToggleController.class); assertThat(controller).isInstanceOf(FakeToggleController.class);
} }
@Test
public void testGetPreferenceController_contextOnly_buildsMatchingController() {
BasePreferenceController controller = SliceBuilderUtils.getPreferenceController(mContext,
getDummyData(PREF_CONTROLLER2));
assertThat(controller).isInstanceOf(FakeContextOnlyPreferenceController.class);
}
@Test @Test
public void testDynamicSummary_returnsSliceSummary() { public void testDynamicSummary_returnsSliceSummary() {
SliceData data = getDummyData(); SliceData data = getDummyData();
@@ -87,7 +95,7 @@ public class SliceBuilderUtilsTest {
@Test @Test
public void testDynamicSummary_returnsFragmentSummary() { public void testDynamicSummary_returnsFragmentSummary() {
SliceData data = getDummyData(null); SliceData data = getDummyData((String) null);
FakePreferenceController controller = spy(new FakePreferenceController(mContext, KEY)); FakePreferenceController controller = spy(new FakePreferenceController(mContext, KEY));
String controllerSummary = "new_Summary"; String controllerSummary = "new_Summary";
doReturn(controllerSummary).when(controller).getSummary(); doReturn(controllerSummary).when(controller).getSummary();
@@ -99,7 +107,7 @@ public class SliceBuilderUtilsTest {
@Test @Test
public void testDynamicSummary_returnsSliceScreenTitle() { public void testDynamicSummary_returnsSliceScreenTitle() {
SliceData data = getDummyData(null); SliceData data = getDummyData((String) null);
FakePreferenceController controller = new FakePreferenceController(mContext, KEY); FakePreferenceController controller = new FakePreferenceController(mContext, KEY);
String summary = SliceBuilderUtils.getSubtitleText(mContext, controller, data); String summary = SliceBuilderUtils.getSubtitleText(mContext, controller, data);
@@ -129,10 +137,18 @@ public class SliceBuilderUtilsTest {
} }
private SliceData getDummyData() { private SliceData getDummyData() {
return getDummyData(SUMMARY); return getDummyData(PREF_CONTROLLER, SUMMARY);
} }
private SliceData getDummyData(String 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() return new SliceData.Builder()
.setKey(KEY) .setKey(KEY)
.setTitle(TITLE) .setTitle(TITLE)
@@ -141,7 +157,7 @@ public class SliceBuilderUtilsTest {
.setIcon(ICON) .setIcon(ICON)
.setFragmentName(FRAGMENT_NAME) .setFragmentName(FRAGMENT_NAME)
.setUri(URI) .setUri(URI)
.setPreferenceControllerClassName(PREF_CONTROLLER) .setPreferenceControllerClassName(prefController.getName())
.build(); .build();
} }
} }