diff --git a/src/com/android/settings/core/BasePreferenceController.java b/src/com/android/settings/core/BasePreferenceController.java index 76250fa700c..9145c3c2efe 100644 --- a/src/com/android/settings/core/BasePreferenceController.java +++ b/src/com/android/settings/core/BasePreferenceController.java @@ -20,6 +20,7 @@ import android.util.Log; import com.android.settings.search.ResultPayload; import com.android.settings.search.SearchIndexableRaw; +import com.android.settings.slices.SliceData; import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.core.lifecycle.Lifecycle; @@ -153,6 +154,14 @@ public abstract class BasePreferenceController extends AbstractPreferenceControl return getAvailabilityStatus() != DISABLED_UNSUPPORTED; } + /** + * @return the UI type supported by the controller. + */ + @SliceData.SliceType + public int getSliceType() { + return SliceData.SliceType.INTENT; + } + /** * Updates non-indexable keys for search provider. * diff --git a/src/com/android/settings/core/TogglePreferenceController.java b/src/com/android/settings/core/TogglePreferenceController.java index 1cf4289e337..cd4131d684f 100644 --- a/src/com/android/settings/core/TogglePreferenceController.java +++ b/src/com/android/settings/core/TogglePreferenceController.java @@ -17,6 +17,7 @@ import android.content.Context; import android.support.v7.preference.Preference; import android.support.v7.preference.TwoStatePreference; +import com.android.settings.slices.SliceData; import com.android.settings.widget.MasterSwitchPreference; /** @@ -59,4 +60,11 @@ public abstract class TogglePreferenceController extends BasePreferenceControlle public final boolean onPreferenceChange(Preference preference, Object newValue) { return setChecked((Boolean) newValue); } + + @Override + @SliceData.SliceType + public int getSliceType() { + return SliceData.SliceType.SWITCH; + } + } \ No newline at end of file diff --git a/src/com/android/settings/slices/SliceBuilderUtils.java b/src/com/android/settings/slices/SliceBuilderUtils.java index 35bc07e3410..fa17fd74398 100644 --- a/src/com/android/settings/slices/SliceBuilderUtils.java +++ b/src/com/android/settings/slices/SliceBuilderUtils.java @@ -23,7 +23,6 @@ import android.content.Context; 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; @@ -67,7 +66,7 @@ public class SliceBuilderUtils { // TODO (b/71640747) Respect setting availability. - if (controller instanceof TogglePreferenceController) { + if (sliceData.getSliceType() == SliceData.SliceType.SWITCH) { addToggleAction(context, builder, ((TogglePreferenceController) controller).isChecked(), sliceData.getKey()); } @@ -77,23 +76,36 @@ public class SliceBuilderUtils { .build(); } + /** + * @return the {@link SliceData.SliceType} for the {@param controllerClassName} and key. + */ + @SliceData.SliceType + public static int getSliceType(Context context, String controllerClassName, + String controllerKey) { + BasePreferenceController controller = getPreferenceController(context, controllerClassName, + controllerKey); + return controller.getSliceType(); + } + /** * Looks at the {@link SliceData#preferenceController} from {@param sliceData} and attempts to * build an {@link AbstractPreferenceController}. */ public static BasePreferenceController getPreferenceController(Context context, SliceData sliceData) { + return getPreferenceController(context, sliceData.getPreferenceController(), + sliceData.getKey()); + } + + private static BasePreferenceController getPreferenceController(Context context, + String controllerClassName, String controllerKey) { try { - return BasePreferenceController.createInstance(context, - sliceData.getPreferenceController()); + return BasePreferenceController.createInstance(context, controllerClassName); } catch (IllegalStateException e) { // Do nothing - Log.d(TAG, "Could not find Context-only controller for preference controller: " - + sliceData.getKey()); } - return BasePreferenceController.createInstance(context, sliceData.getPreferenceController(), - sliceData.getKey()); + return BasePreferenceController.createInstance(context, controllerClassName, controllerKey); } private static void addToggleAction(Context context, RowBuilder builder, boolean isChecked, diff --git a/src/com/android/settings/slices/SliceData.java b/src/com/android/settings/slices/SliceData.java index f72add75828..a7c9a116dad 100644 --- a/src/com/android/settings/slices/SliceData.java +++ b/src/com/android/settings/slices/SliceData.java @@ -16,76 +16,111 @@ package com.android.settings.slices; +import android.annotation.IntDef; import android.net.Uri; import android.text.TextUtils; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + /** * Data class representing a slice stored by {@link SlicesIndexer}. - * Note that {@link #key} is treated as a primary key for this class and determines equality. + * Note that {@link #mKey} is treated as a primary key for this class and determines equality. */ public class SliceData { - private final String key; + /** + * Flags indicating the UI type of the Slice. + */ + @IntDef({SliceType.INTENT, SliceType.SWITCH, SliceType.SLIDER}) + @Retention(RetentionPolicy.SOURCE) + public @interface SliceType { + /** + * Only supports content intent. + */ + int INTENT = 0; - private final String title; + /** + * Supports toggle action. + */ + int SWITCH = 1; - private final String summary; + /** + * Supports progress bar. + */ + int SLIDER = 2; + } - private final String screenTitle; + private final String mKey; - private final int iconResource; + private final String mTitle; - private final String fragmentClassName; + private final String mSummary; - private final Uri uri; + private final String mScreenTitle; - private final String preferenceController; + private final int mIconResource; + + private final String mFragmentClassName; + + private final Uri mUri; + + private final String mPreferenceController; + + @SliceType + private final int mSliceType; public String getKey() { - return key; + return mKey; } public String getTitle() { - return title; + return mTitle; } public String getSummary() { - return summary; + return mSummary; } public String getScreenTitle() { - return screenTitle; + return mScreenTitle; } public int getIconResource() { - return iconResource; + return mIconResource; } public String getFragmentClassName() { - return fragmentClassName; + return mFragmentClassName; } public Uri getUri() { - return uri; + return mUri; } public String getPreferenceController() { - return preferenceController; + return mPreferenceController; + } + + public int getSliceType() { + return mSliceType; } private SliceData(Builder builder) { - key = builder.mKey; - title = builder.mTitle; - summary = builder.mSummary; - screenTitle = builder.mScreenTitle; - iconResource = builder.mIconResource; - fragmentClassName = builder.mFragmentClassName; - uri = builder.mUri; - preferenceController = builder.mPrefControllerClassName; + mKey = builder.mKey; + mTitle = builder.mTitle; + mSummary = builder.mSummary; + mScreenTitle = builder.mScreenTitle; + mIconResource = builder.mIconResource; + mFragmentClassName = builder.mFragmentClassName; + mUri = builder.mUri; + mPreferenceController = builder.mPrefControllerClassName; + mSliceType = builder.mSliceType; } @Override public int hashCode() { - return key.hashCode(); + return mKey.hashCode(); } @Override @@ -94,7 +129,7 @@ public class SliceData { return false; } SliceData newObject = (SliceData) obj; - return TextUtils.equals(key, newObject.key); + return TextUtils.equals(mKey, newObject.mKey); } static class Builder { @@ -114,6 +149,8 @@ public class SliceData { private String mPrefControllerClassName; + private int mSliceType; + public Builder setKey(String key) { mKey = key; return this; @@ -154,6 +191,11 @@ public class SliceData { return this; } + public Builder setSliceType(@SliceType int sliceType) { + mSliceType = sliceType; + 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 a023b160a79..d77f427e282 100644 --- a/src/com/android/settings/slices/SliceDataConverter.java +++ b/src/com/android/settings/slices/SliceDataConverter.java @@ -127,11 +127,6 @@ class SliceDataConverter { XmlResourceParser parser = null; final List xmlSliceData = new ArrayList<>(); - String key; - String title; - String summary; - @DrawableRes int iconResId; - String controllerClassName; try { parser = mContext.getResources().getXml(xmlResId); @@ -155,30 +150,33 @@ class SliceDataConverter { // TODO (b/67996923) Investigate if we need headers for Slices, since they never // correspond to an actual setting. - SliceData xmlSlice; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { continue; } - // TODO (b/67996923) Non-controller Slices should become intent-only slices. // Note that without a controller, dynamic summaries are impossible. // TODO (b/67996923) This will not work if preferences have nested intents: // // - controllerClassName = PreferenceXmlParserUtils.getController(mContext, attrs); + final String controllerClassName = PreferenceXmlParserUtils.getController(mContext, + attrs); if (TextUtils.isEmpty(controllerClassName)) { continue; } - title = PreferenceXmlParserUtils.getDataTitle(mContext, attrs); - key = PreferenceXmlParserUtils.getDataKey(mContext, attrs); - iconResId = PreferenceXmlParserUtils.getDataIcon(mContext, attrs); - summary = PreferenceXmlParserUtils.getDataSummary(mContext, attrs); + final String title = PreferenceXmlParserUtils.getDataTitle(mContext, attrs); + final String key = PreferenceXmlParserUtils.getDataKey(mContext, attrs); + @DrawableRes final int iconResId = PreferenceXmlParserUtils.getDataIcon(mContext, + attrs); + final String summary = PreferenceXmlParserUtils.getDataSummary(mContext, attrs); + final int sliceType = SliceBuilderUtils.getSliceType(mContext, controllerClassName, + key); - xmlSlice = new SliceData.Builder() + final SliceData xmlSlice = new SliceData.Builder() .setKey(key) .setTitle(title) .setSummary(summary) @@ -186,6 +184,7 @@ class SliceDataConverter { .setScreenTitle(screenTitle) .setPreferenceControllerClassName(controllerClassName) .setFragmentName(fragmentName) + .setSliceType(sliceType) .build(); xmlSliceData.add(xmlSlice); diff --git a/tests/robotests/assets/grandfather_slice_controller_not_in_xml b/tests/robotests/assets/grandfather_slice_controller_not_in_xml index f11027e6686..1a67726fd47 100644 --- a/tests/robotests/assets/grandfather_slice_controller_not_in_xml +++ b/tests/robotests/assets/grandfather_slice_controller_not_in_xml @@ -1 +1,2 @@ -com.android.settings.testutils.FakeToggleController \ No newline at end of file +com.android.settings.testutils.FakeToggleController +com.android.settings.core.TogglePreferenceControllerTest$FakeToggle diff --git a/tests/robotests/src/com/android/settings/core/BasePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/core/BasePreferenceControllerTest.java index 3c0740b4f36..3949652ee50 100644 --- a/tests/robotests/src/com/android/settings/core/BasePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/core/BasePreferenceControllerTest.java @@ -24,6 +24,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.when; import com.android.settings.TestConfig; +import com.android.settings.slices.SliceData; import com.android.settings.testutils.SettingsRobolectricTestRunner; import org.junit.Before; @@ -126,4 +127,9 @@ public class BasePreferenceControllerTest { assertThat(mPreferenceController.isSupported()).isTrue(); } + + @Test + public void getSliceType_shouldReturnIntent() { + assertThat(mPreferenceController.getSliceType()).isEqualTo(SliceData.SliceType.INTENT); + } } \ No newline at end of file diff --git a/tests/robotests/src/com/android/settings/core/TogglePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/core/TogglePreferenceControllerTest.java index 099c9baaea4..ab770f1ea1e 100644 --- a/tests/robotests/src/com/android/settings/core/TogglePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/core/TogglePreferenceControllerTest.java @@ -17,20 +17,16 @@ package com.android.settings.core; import static com.google.common.truth.Truth.assertThat; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - import android.content.Context; import android.support.v14.preference.SwitchPreference; import com.android.settings.TestConfig; +import com.android.settings.slices.SliceData; import com.android.settings.testutils.SettingsRobolectricTestRunner; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; @@ -38,35 +34,34 @@ import org.robolectric.annotation.Config; @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) public class TogglePreferenceControllerTest { - @Mock - TogglePreferenceController mTogglePreferenceController; + FakeToggle mToggleController; Context mContext; SwitchPreference mPreference; @Before public void setUp() { - MockitoAnnotations.initMocks(this); mContext = RuntimeEnvironment.application; mPreference = new SwitchPreference(mContext); + mToggleController = new FakeToggle(mContext, "key"); } @Test public void testSetsPreferenceValue_setsChecked() { - when(mTogglePreferenceController.isChecked()).thenReturn(true); + mToggleController.setChecked(true); mPreference.setChecked(false); - mTogglePreferenceController.updateState(mPreference); + mToggleController.updateState(mPreference); assertThat(mPreference.isChecked()).isTrue(); } @Test public void testSetsPreferenceValue_setsNotChecked() { - when(mTogglePreferenceController.isChecked()).thenReturn(false); + mToggleController.setChecked(false); mPreference.setChecked(true); - mTogglePreferenceController.updateState(mPreference); + mToggleController.updateState(mPreference); assertThat(mPreference.isChecked()).isFalse(); } @@ -74,18 +69,51 @@ public class TogglePreferenceControllerTest { @Test public void testUpdatesPreferenceOnChange_turnsOn() { boolean newValue = true; + mToggleController.setChecked(!newValue); - mTogglePreferenceController.onPreferenceChange(mPreference, newValue); + mToggleController.onPreferenceChange(mPreference, newValue); - verify(mTogglePreferenceController).setChecked(newValue); + assertThat(mToggleController.isChecked()).isEqualTo(newValue); } @Test public void testUpdatesPreferenceOnChange_turnsOff() { boolean newValue = false; + mToggleController.setChecked(!newValue); - mTogglePreferenceController.onPreferenceChange(mPreference, newValue); + mToggleController.onPreferenceChange(mPreference, newValue); - verify(mTogglePreferenceController).setChecked(newValue); + assertThat(mToggleController.isChecked()).isEqualTo(newValue); + } + + @Test + public void testSliceType_returnsSliceType() { + assertThat(mToggleController.getSliceType()).isEqualTo( + SliceData.SliceType.SWITCH); + } + + private static class FakeToggle extends TogglePreferenceController { + + private boolean checkedFlag; + + public FakeToggle(Context context, String preferenceKey) { + super(context, preferenceKey); + } + + @Override + public boolean isChecked() { + return checkedFlag; + } + + @Override + public boolean setChecked(boolean isChecked) { + checkedFlag = isChecked; + return true; + } + + @Override + public int getAvailabilityStatus() { + return AVAILABLE; + } } } diff --git a/tests/robotests/src/com/android/settings/slices/FakePreferenceController.java b/tests/robotests/src/com/android/settings/slices/FakePreferenceController.java index f62380f403e..6c861dbb344 100644 --- a/tests/robotests/src/com/android/settings/slices/FakePreferenceController.java +++ b/tests/robotests/src/com/android/settings/slices/FakePreferenceController.java @@ -30,4 +30,9 @@ public class FakePreferenceController extends BasePreferenceController { public int getAvailabilityStatus() { return AVAILABLE; } + + @Override + public int getSliceType() { + return SliceData.SliceType.SLIDER; + } } diff --git a/tests/robotests/src/com/android/settings/slices/SliceDataConverterTest.java b/tests/robotests/src/com/android/settings/slices/SliceDataConverterTest.java index 1d0ac415e08..98a7d6cf782 100644 --- a/tests/robotests/src/com/android/settings/slices/SliceDataConverterTest.java +++ b/tests/robotests/src/com/android/settings/slices/SliceDataConverterTest.java @@ -90,5 +90,6 @@ public class SliceDataConverterTest { assertThat(fakeSlice.getUri()).isNull(); assertThat(fakeSlice.getFragmentClassName()).isEqualTo(fakeFragmentClassName); assertThat(fakeSlice.getPreferenceController()).isEqualTo(fakeControllerName); + assertThat(fakeSlice.getSliceType()).isEqualTo(SliceData.SliceType.SLIDER); } } \ 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 82183e4a88f..ee6fe969651 100644 --- a/tests/robotests/src/com/android/settings/slices/SliceDataTest.java +++ b/tests/robotests/src/com/android/settings/slices/SliceDataTest.java @@ -40,6 +40,7 @@ public class SliceDataTest { 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 int SLICE_TYPE = SliceData.SliceType.SWITCH; @Test public void testBuilder_buildsMatchingObject() { @@ -51,7 +52,8 @@ public class SliceDataTest { .setIcon(ICON) .setFragmentName(FRAGMENT_NAME) .setUri(URI) - .setPreferenceControllerClassName(PREF_CONTROLLER); + .setPreferenceControllerClassName(PREF_CONTROLLER) + .setSliceType(SLICE_TYPE); SliceData data = builder.build(); @@ -63,6 +65,7 @@ public class SliceDataTest { assertThat(data.getFragmentClassName()).isEqualTo(FRAGMENT_NAME); assertThat(data.getUri()).isEqualTo(URI); assertThat(data.getPreferenceController()).isEqualTo(PREF_CONTROLLER); + assertThat(data.getSliceType()).isEqualTo(SLICE_TYPE); } @Test(expected = IllegalStateException.class)