Adding the ability to customize the subtitle on an unavailable slice

When a slice is depending on some setting and the setting is off,
it shows "depends on another setting".
Add an new attribute for Preference to customize the subtitle when
a slice is unavailable.

Bug: 118399193
Test: Robo test on com.android.settings.slices, com.android.settings.core
Change-Id: I84a8400295b36abb357e5baf98e9be3a8d6ea897
This commit is contained in:
Console Chen
2018-12-19 18:01:09 +08:00
parent e5e94b95dc
commit ce16d7ad63
17 changed files with 256 additions and 31 deletions

View File

@@ -72,6 +72,8 @@
<attr name="platform_slice" format="boolean" /> <attr name="platform_slice" format="boolean" />
<!-- Whether or not dynamic summary text from PreferenceController is allowed when creating slice object, by default it's false. --> <!-- Whether or not dynamic summary text from PreferenceController is allowed when creating slice object, by default it's false. -->
<attr name="allowDynamicSummaryInSlice" format="boolean" /> <attr name="allowDynamicSummaryInSlice" format="boolean" />
<!-- customized subtitle if it's an unavailable slice -->
<attr name="unavailableSliceSubtitle" format="string" />
</declare-styleable> </declare-styleable>
<declare-styleable name="PreferenceScreen"> <declare-styleable name="PreferenceScreen">

View File

@@ -72,9 +72,11 @@ public class PreferenceXmlParserUtils {
MetadataFlag.FLAG_NEED_PREF_SUMMARY, MetadataFlag.FLAG_NEED_PREF_SUMMARY,
MetadataFlag.FLAG_NEED_PREF_ICON, MetadataFlag.FLAG_NEED_PREF_ICON,
MetadataFlag.FLAG_NEED_SEARCHABLE, MetadataFlag.FLAG_NEED_SEARCHABLE,
MetadataFlag.FLAG_ALLOW_DYNAMIC_SUMMARY_IN_SLICE}) MetadataFlag.FLAG_ALLOW_DYNAMIC_SUMMARY_IN_SLICE,
MetadataFlag.FLAG_UNAVAILABLE_SLICE_SUBTITLE})
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
public @interface MetadataFlag { public @interface MetadataFlag {
int FLAG_INCLUDE_PREF_SCREEN = 1; int FLAG_INCLUDE_PREF_SCREEN = 1;
int FLAG_NEED_KEY = 1 << 1; int FLAG_NEED_KEY = 1 << 1;
int FLAG_NEED_PREF_TYPE = 1 << 2; int FLAG_NEED_PREF_TYPE = 1 << 2;
@@ -87,6 +89,7 @@ public class PreferenceXmlParserUtils {
int FLAG_NEED_SEARCHABLE = 1 << 9; int FLAG_NEED_SEARCHABLE = 1 << 9;
int FLAG_ALLOW_DYNAMIC_SUMMARY_IN_SLICE = 1 << 10; int FLAG_ALLOW_DYNAMIC_SUMMARY_IN_SLICE = 1 << 10;
int FLAG_NEED_PREF_APPEND = 1 << 11; int FLAG_NEED_PREF_APPEND = 1 << 11;
int FLAG_UNAVAILABLE_SLICE_SUBTITLE = 1 << 12;
} }
public static final String METADATA_PREF_TYPE = "type"; public static final String METADATA_PREF_TYPE = "type";
@@ -101,6 +104,8 @@ public class PreferenceXmlParserUtils {
public static final String METADATA_ALLOW_DYNAMIC_SUMMARY_IN_SLICE = public static final String METADATA_ALLOW_DYNAMIC_SUMMARY_IN_SLICE =
"allow_dynamic_summary_in_slice"; "allow_dynamic_summary_in_slice";
public static final String METADATA_APPEND = "staticPreferenceLocation"; public static final String METADATA_APPEND = "staticPreferenceLocation";
public static final String METADATA_UNAVAILABLE_SLICE_SUBTITLE =
"unavailable_slice_subtitle";
private static final String ENTRIES_SEPARATOR = "|"; private static final String ENTRIES_SEPARATOR = "|";
@@ -249,6 +254,10 @@ public class PreferenceXmlParserUtils {
preferenceMetadata.putBoolean(METADATA_APPEND, preferenceMetadata.putBoolean(METADATA_APPEND,
isAppended(preferenceScreenAttributes)); isAppended(preferenceScreenAttributes));
} }
if (hasFlag(flags, MetadataFlag.FLAG_UNAVAILABLE_SLICE_SUBTITLE)) {
preferenceMetadata.putString(METADATA_UNAVAILABLE_SLICE_SUBTITLE,
getUnavailableSliceSubtitle(preferenceAttributes));
}
metadata.add(preferenceMetadata); metadata.add(preferenceMetadata);
preferenceAttributes.recycle(); preferenceAttributes.recycle();
@@ -344,6 +353,11 @@ public class PreferenceXmlParserUtils {
private static boolean isAppended(TypedArray styledAttributes) { private static boolean isAppended(TypedArray styledAttributes) {
return styledAttributes.getInt(R.styleable.PreferenceScreen_staticPreferenceLocation, return styledAttributes.getInt(R.styleable.PreferenceScreen_staticPreferenceLocation,
PREPEND_VALUE) == APPEND_VALUE; PREPEND_VALUE) == APPEND_VALUE;
} }
}
private static String getUnavailableSliceSubtitle(TypedArray styledAttributes) {
return styledAttributes.getString(
R.styleable.Preference_unavailableSliceSubtitle);
}
}

View File

@@ -425,7 +425,10 @@ public class SliceBuilderUtils {
final String title = data.getTitle(); final String title = data.getTitle();
final Set<String> keywords = buildSliceKeywords(data); final Set<String> keywords = buildSliceKeywords(data);
@ColorInt final int color = Utils.getColorAccentDefaultColor(context); @ColorInt final int color = Utils.getColorAccentDefaultColor(context);
final CharSequence summary = context.getText(R.string.disabled_dependent_setting_summary);
final String customSubtitle = data.getUnavailableSliceSubtitle();
final CharSequence subtitle = !TextUtils.isEmpty(customSubtitle) ? customSubtitle
: context.getText(R.string.disabled_dependent_setting_summary);
final IconCompat icon = getSafeIcon(context, data); final IconCompat icon = getSafeIcon(context, data);
final SliceAction primaryAction = SliceAction.createDeeplink( final SliceAction primaryAction = SliceAction.createDeeplink(
getContentPendingIntent(context, data), getContentPendingIntent(context, data),
@@ -436,7 +439,7 @@ public class SliceBuilderUtils {
.addRow(new RowBuilder() .addRow(new RowBuilder()
.setTitle(title) .setTitle(title)
.setTitleItem(icon, ListBuilder.ICON_IMAGE) .setTitleItem(icon, ListBuilder.ICON_IMAGE)
.setSubtitle(summary) .setSubtitle(subtitle)
.setPrimaryAction(primaryAction)) .setPrimaryAction(primaryAction))
.setKeywords(keywords) .setKeywords(keywords)
.build(); .build();

View File

@@ -28,7 +28,6 @@ import java.lang.annotation.RetentionPolicy;
* Note that {@link #mKey} 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 { public class SliceData {
/** /**
* Flags indicating the UI type of the Slice. * Flags indicating the UI type of the Slice.
*/ */
@@ -76,6 +75,8 @@ public class SliceData {
private final boolean mIsDynamicSummaryAllowed; private final boolean mIsDynamicSummaryAllowed;
private final String mUnavailableSliceSubtitle;
public String getKey() { public String getKey() {
return mKey; return mKey;
} }
@@ -124,6 +125,10 @@ public class SliceData {
return mIsDynamicSummaryAllowed; return mIsDynamicSummaryAllowed;
} }
public String getUnavailableSliceSubtitle() {
return mUnavailableSliceSubtitle;
}
private SliceData(Builder builder) { private SliceData(Builder builder) {
mKey = builder.mKey; mKey = builder.mKey;
mTitle = builder.mTitle; mTitle = builder.mTitle;
@@ -137,6 +142,7 @@ public class SliceData {
mSliceType = builder.mSliceType; mSliceType = builder.mSliceType;
mIsPlatformDefined = builder.mIsPlatformDefined; mIsPlatformDefined = builder.mIsPlatformDefined;
mIsDynamicSummaryAllowed = builder.mIsDynamicSummaryAllowed; mIsDynamicSummaryAllowed = builder.mIsDynamicSummaryAllowed;
mUnavailableSliceSubtitle = builder.mUnavailableSliceSubtitle;
} }
@Override @Override
@@ -178,6 +184,8 @@ public class SliceData {
private boolean mIsDynamicSummaryAllowed; private boolean mIsDynamicSummaryAllowed;
private String mUnavailableSliceSubtitle;
public Builder setKey(String key) { public Builder setKey(String key) {
mKey = key; mKey = key;
return this; return this;
@@ -238,6 +246,12 @@ public class SliceData {
return this; return this;
} }
public Builder setUnavailableSliceSubtitle(
String unavailableSliceSubtitle) {
mUnavailableSliceSubtitle = unavailableSliceSubtitle;
return this;
}
public SliceData build() { public SliceData build() {
if (TextUtils.isEmpty(mKey)) { if (TextUtils.isEmpty(mKey)) {
throw new InvalidSliceDataException("Key cannot be empty"); throw new InvalidSliceDataException("Key cannot be empty");

View File

@@ -16,12 +16,12 @@
package com.android.settings.slices; package com.android.settings.slices;
import static com.android.settings.core.PreferenceXmlParserUtils import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_ALLOW_DYNAMIC_SUMMARY_IN_SLICE;
.METADATA_ALLOW_DYNAMIC_SUMMARY_IN_SLICE;
import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_CONTROLLER; 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_ICON;
import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_KEY; 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_PLATFORM_SLICE_FLAG;
import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_UNAVAILABLE_SLICE_SUBTITLE;
import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_SUMMARY; import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_SUMMARY;
import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_TITLE; import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_TITLE;
@@ -189,7 +189,8 @@ class SliceDataConverter {
| MetadataFlag.FLAG_NEED_PREF_ICON | MetadataFlag.FLAG_NEED_PREF_ICON
| MetadataFlag.FLAG_NEED_PREF_SUMMARY | MetadataFlag.FLAG_NEED_PREF_SUMMARY
| MetadataFlag.FLAG_NEED_PLATFORM_SLICE_FLAG | MetadataFlag.FLAG_NEED_PLATFORM_SLICE_FLAG
| MetadataFlag.FLAG_ALLOW_DYNAMIC_SUMMARY_IN_SLICE); | MetadataFlag.FLAG_ALLOW_DYNAMIC_SUMMARY_IN_SLICE
| MetadataFlag.FLAG_UNAVAILABLE_SLICE_SUBTITLE);
for (Bundle bundle : metadata) { for (Bundle bundle : metadata) {
// TODO (b/67996923) Non-controller Slices should become intent-only slices. // TODO (b/67996923) Non-controller Slices should become intent-only slices.
@@ -208,6 +209,8 @@ class SliceDataConverter {
final boolean isPlatformSlice = bundle.getBoolean(METADATA_PLATFORM_SLICE_FLAG); final boolean isPlatformSlice = bundle.getBoolean(METADATA_PLATFORM_SLICE_FLAG);
final boolean isDynamicSummaryAllowed = bundle.getBoolean( final boolean isDynamicSummaryAllowed = bundle.getBoolean(
METADATA_ALLOW_DYNAMIC_SUMMARY_IN_SLICE); METADATA_ALLOW_DYNAMIC_SUMMARY_IN_SLICE);
final String unavailableSliceSubtitle = bundle.getString(
METADATA_UNAVAILABLE_SLICE_SUBTITLE);
final SliceData xmlSlice = new SliceData.Builder() final SliceData xmlSlice = new SliceData.Builder()
.setKey(key) .setKey(key)
@@ -220,6 +223,7 @@ class SliceDataConverter {
.setSliceType(sliceType) .setSliceType(sliceType)
.setPlatformDefined(isPlatformSlice) .setPlatformDefined(isPlatformSlice)
.setDynamicSummaryAllowed(isDynamicSummaryAllowed) .setDynamicSummaryAllowed(isDynamicSummaryAllowed)
.setUnavailableSliceSubtitle(unavailableSliceSubtitle)
.build(); .build();
final BasePreferenceController controller = final BasePreferenceController controller =

View File

@@ -50,6 +50,7 @@ public class SlicesDatabaseAccessor {
IndexColumns.PLATFORM_SLICE, IndexColumns.PLATFORM_SLICE,
IndexColumns.SLICE_TYPE, IndexColumns.SLICE_TYPE,
IndexColumns.ALLOW_DYNAMIC_SUMMARY_IN_SLICE, IndexColumns.ALLOW_DYNAMIC_SUMMARY_IN_SLICE,
IndexColumns.UNAVAILABLE_SLICE_SUBTITLE,
}; };
// Cursor value for boolean true // Cursor value for boolean true
@@ -167,6 +168,8 @@ public class SlicesDatabaseAccessor {
cursor.getColumnIndex(IndexColumns.ALLOW_DYNAMIC_SUMMARY_IN_SLICE)) == TRUE; cursor.getColumnIndex(IndexColumns.ALLOW_DYNAMIC_SUMMARY_IN_SLICE)) == TRUE;
int sliceType = cursor.getInt( int sliceType = cursor.getInt(
cursor.getColumnIndex(IndexColumns.SLICE_TYPE)); cursor.getColumnIndex(IndexColumns.SLICE_TYPE));
final String unavailableSliceSubtitle = cursor.getString(
cursor.getColumnIndex(IndexColumns.UNAVAILABLE_SLICE_SUBTITLE));
if (isIntentOnly) { if (isIntentOnly) {
sliceType = SliceData.SliceType.INTENT; sliceType = SliceData.SliceType.INTENT;
@@ -185,6 +188,7 @@ public class SlicesDatabaseAccessor {
.setPlatformDefined(isPlatformDefined) .setPlatformDefined(isPlatformDefined)
.setSliceType(sliceType) .setSliceType(sliceType)
.setDynamicSummaryAllowed(isDynamicSummaryAllowed) .setDynamicSummaryAllowed(isDynamicSummaryAllowed)
.setUnavailableSliceSubtitle(unavailableSliceSubtitle)
.build(); .build();
} }

View File

@@ -36,7 +36,7 @@ public class SlicesDatabaseHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "slices_index.db"; private static final String DATABASE_NAME = "slices_index.db";
private static final String SHARED_PREFS_TAG = "slices_shared_prefs"; private static final String SHARED_PREFS_TAG = "slices_shared_prefs";
private static final int DATABASE_VERSION = 3; private static final int DATABASE_VERSION = 4;
public interface Tables { public interface Tables {
String TABLE_SLICES_INDEX = "slices_index"; String TABLE_SLICES_INDEX = "slices_index";
@@ -99,6 +99,11 @@ public class SlicesDatabaseHelper extends SQLiteOpenHelper {
* preference controller. * preference controller.
*/ */
String ALLOW_DYNAMIC_SUMMARY_IN_SLICE = "allow_dynamic_summary_in_slice"; String ALLOW_DYNAMIC_SUMMARY_IN_SLICE = "allow_dynamic_summary_in_slice";
/**
* Customized subtitle if it's a unavailable slice
*/
String UNAVAILABLE_SLICE_SUBTITLE = "unavailable_slice_subtitle";
} }
private static final String CREATE_SLICES_TABLE = private static final String CREATE_SLICES_TABLE =
@@ -125,6 +130,8 @@ public class SlicesDatabaseHelper extends SQLiteOpenHelper {
IndexColumns.SLICE_TYPE + IndexColumns.SLICE_TYPE +
", " + ", " +
IndexColumns.ALLOW_DYNAMIC_SUMMARY_IN_SLICE + IndexColumns.ALLOW_DYNAMIC_SUMMARY_IN_SLICE +
", " +
IndexColumns.UNAVAILABLE_SLICE_SUBTITLE +
");"; ");";
private final Context mContext; private final Context mContext;
@@ -151,7 +158,7 @@ public class SlicesDatabaseHelper extends SQLiteOpenHelper {
@Override @Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion < DATABASE_VERSION) { if (oldVersion < DATABASE_VERSION) {
Log.d(TAG, "Reconstructing DB from " + oldVersion + "to " + newVersion); Log.d(TAG, "Reconstructing DB from " + oldVersion + " to " + newVersion);
reconstruct(db); reconstruct(db);
} }
} }

View File

@@ -113,6 +113,8 @@ class SlicesIndexer implements Runnable {
values.put(IndexColumns.SLICE_TYPE, dataRow.getSliceType()); values.put(IndexColumns.SLICE_TYPE, dataRow.getSliceType());
values.put(IndexColumns.ALLOW_DYNAMIC_SUMMARY_IN_SLICE, values.put(IndexColumns.ALLOW_DYNAMIC_SUMMARY_IN_SLICE,
dataRow.isDynamicSummaryAllowed()); dataRow.isDynamicSummaryAllowed());
values.put(IndexColumns.UNAVAILABLE_SLICE_SUBTITLE,
dataRow.getUnavailableSliceSubtitle());
database.replaceOrThrow(Tables.TABLE_SLICES_INDEX, null /* nullColumnHack */, database.replaceOrThrow(Tables.TABLE_SLICES_INDEX, null /* nullColumnHack */,
values); values);

View File

@@ -27,6 +27,7 @@
settings:controller="com.android.settings.slices.FakePreferenceController" settings:controller="com.android.settings.slices.FakePreferenceController"
settings:keywords="a, b, c" settings:keywords="a, b, c"
settings:platform_slice="true" settings:platform_slice="true"
settings:allowDynamicSummaryInSlice="true"/> settings:allowDynamicSummaryInSlice="true"
settings:unavailableSliceSubtitle="subtitleOfUnavailableSlice"/>
</PreferenceScreen> </PreferenceScreen>

View File

@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2018 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:key="fake_title_key"
android:title="screen_title">
<Preference
android:key="key1"
android:title="title"
android:icon="@drawable/ic_android"
android:summary="summary"
settings:controller="com.android.settings.slices.FakePreferenceController"
settings:keywords="keyword"
settings:platform_slice="true"/>
<Preference
android:key="key2"
android:title="title"
android:icon="@drawable/ic_android"
android:summary="summary"
settings:controller="com.android.settings.slices.FakePreferenceController"
settings:keywords="keyword"
settings:platform_slice="true"
settings:unavailableSliceSubtitle="subtitleOfUnavailable"/>
</PreferenceScreen>

View File

@@ -16,12 +16,12 @@
package com.android.settings.core; package com.android.settings.core;
import static com.android.settings.core.PreferenceXmlParserUtils import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_ALLOW_DYNAMIC_SUMMARY_IN_SLICE;
.METADATA_ALLOW_DYNAMIC_SUMMARY_IN_SLICE;
import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_APPEND; import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_APPEND;
import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_KEY; import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_KEY;
import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_KEYWORDS; import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_KEYWORDS;
import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_SEARCHABLE; import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_SEARCHABLE;
import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_UNAVAILABLE_SLICE_SUBTITLE;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
@@ -35,7 +35,6 @@ import android.util.Xml;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.core.PreferenceXmlParserUtils.MetadataFlag; import com.android.settings.core.PreferenceXmlParserUtils.MetadataFlag;
import java.util.Objects;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@@ -47,6 +46,7 @@ import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.Objects;
/** /**
* These tests use a series of preferences that have specific attributes which are sometimes * These tests use a series of preferences that have specific attributes which are sometimes
@@ -320,7 +320,7 @@ public class PreferenceXmlParserUtilsTest {
@Test @Test
@Config(qualifiers = "mcc999") @Config(qualifiers = "mcc999")
public void extractMetadata_requestAppendProperty_shouldDefaultToFalse() public void extractMetadata_requestAppendProperty_shouldDefaultToFalse()
throws Exception { throws Exception {
final List<Bundle> metadata = PreferenceXmlParserUtils.extractMetadata(mContext, final List<Bundle> metadata = PreferenceXmlParserUtils.extractMetadata(mContext,
R.xml.display_settings, R.xml.display_settings,
MetadataFlag.FLAG_INCLUDE_PREF_SCREEN | MetadataFlag.FLAG_NEED_PREF_APPEND); MetadataFlag.FLAG_INCLUDE_PREF_SCREEN | MetadataFlag.FLAG_NEED_PREF_APPEND);
@@ -333,7 +333,7 @@ public class PreferenceXmlParserUtilsTest {
@Test @Test
@Config(qualifiers = "mcc999") @Config(qualifiers = "mcc999")
public void extractMetadata_requestAppendProperty_shouldReturnCorrectValue() public void extractMetadata_requestAppendProperty_shouldReturnCorrectValue()
throws Exception { throws Exception {
final List<Bundle> metadata = PreferenceXmlParserUtils.extractMetadata(mContext, final List<Bundle> metadata = PreferenceXmlParserUtils.extractMetadata(mContext,
R.xml.battery_saver_schedule_settings, R.xml.battery_saver_schedule_settings,
MetadataFlag.FLAG_INCLUDE_PREF_SCREEN | MetadataFlag.FLAG_NEED_PREF_APPEND); MetadataFlag.FLAG_INCLUDE_PREF_SCREEN | MetadataFlag.FLAG_NEED_PREF_APPEND);
@@ -343,6 +343,46 @@ public class PreferenceXmlParserUtilsTest {
} }
} }
@Test
@Config(qualifiers = "mcc999")
public void extractMetadata_requestUnavailableSliceSubtitle_shouldDefaultNull()
throws Exception {
final List<Bundle> metadata = PreferenceXmlParserUtils.extractMetadata(mContext,
R.xml.night_display_settings,
MetadataFlag.FLAG_NEED_KEY | MetadataFlag.FLAG_UNAVAILABLE_SLICE_SUBTITLE);
boolean bundleWithKey1Found = false;
for (Bundle bundle : metadata) {
if (bundle.getString(METADATA_KEY).equals("key1")) {
assertThat(bundle.getString(METADATA_UNAVAILABLE_SLICE_SUBTITLE)).isNull();
bundleWithKey1Found = true;
break;
}
}
assertThat(bundleWithKey1Found).isTrue();
}
@Test
@Config(qualifiers = "mcc999")
public void extractMetadata_requestUnavailableSliceSubtitle_shouldReturnAttributeValue()
throws Exception {
final String expectedSubtitle = "subtitleOfUnavailable";
final List<Bundle> metadata = PreferenceXmlParserUtils.extractMetadata(mContext,
R.xml.night_display_settings,
MetadataFlag.FLAG_NEED_KEY | MetadataFlag.FLAG_UNAVAILABLE_SLICE_SUBTITLE);
boolean bundleWithKey2Found = false;
for (Bundle bundle : metadata) {
if (bundle.getString(METADATA_KEY).equals("key2")) {
assertThat(bundle.getString(METADATA_UNAVAILABLE_SLICE_SUBTITLE)).isEqualTo(
expectedSubtitle);
bundleWithKey2Found = true;
break;
}
}
assertThat(bundleWithKey2Found).isTrue();
}
/** /**
* @param resId the ID for the XML preference * @param resId the ID for the XML preference
* @return an XML resource parser that points to the start tag * @return an XML resource parser that points to the start tag

View File

@@ -449,7 +449,7 @@ public class SliceBuilderUtilsTest {
R.drawable.ic_settings).toIcon().getResId(); R.drawable.ic_settings).toIcon().getResId();
final SliceData data = getDummyData(FakeUnavailablePreferenceController.class, final SliceData data = getDummyData(FakeUnavailablePreferenceController.class,
SUMMARY, SliceData.SliceType.SWITCH, SCREEN_TITLE, 0 /* icon */, SUMMARY, SliceData.SliceType.SWITCH, SCREEN_TITLE, 0 /* icon */,
IS_DYNAMIC_SUMMARY_ALLOWED); IS_DYNAMIC_SUMMARY_ALLOWED, null /* unavailableSliceSubtitle */);
Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.putInt(mContext.getContentResolver(),
FakeUnavailablePreferenceController.AVAILABILITY_KEY, FakeUnavailablePreferenceController.AVAILABILITY_KEY,
BasePreferenceController.DISABLED_DEPENDENT_SETTING); BasePreferenceController.DISABLED_DEPENDENT_SETTING);
@@ -518,33 +518,65 @@ public class SliceBuilderUtilsTest {
assertThat(actualIconResource).isEqualTo(settingsIcon); assertThat(actualIconResource).isEqualTo(settingsIcon);
} }
@Test
public void buildUnavailableSlice_customizeSubtitle_returnsSliceWithCustomizedSubtitle() {
final String subtitleOfUnavailableSlice = "subtitleOfUnavailableSlice";
final SliceData data = getDummyData(FakeUnavailablePreferenceController.class,
SUMMARY, SliceData.SliceType.SWITCH, SCREEN_TITLE, 0 /* icon */,
IS_DYNAMIC_SUMMARY_ALLOWED, subtitleOfUnavailableSlice);
Settings.Global.putInt(mContext.getContentResolver(),
FakeUnavailablePreferenceController.AVAILABILITY_KEY,
BasePreferenceController.DISABLED_DEPENDENT_SETTING);
final Slice slice = SliceBuilderUtils.buildSlice(mContext, data);
final SliceMetadata metadata = SliceMetadata.from(mContext, slice);
assertThat(metadata.getSubtitle()).isEqualTo(subtitleOfUnavailableSlice);
}
@Test
public void buildUnavailableSlice_notCustomizeSubtitle_returnsSliceWithDefaultSubtitle() {
final SliceData data = getDummyData(FakeUnavailablePreferenceController.class,
SliceData.SliceType.SWITCH);
Settings.Global.putInt(mContext.getContentResolver(),
FakeUnavailablePreferenceController.AVAILABILITY_KEY,
BasePreferenceController.DISABLED_DEPENDENT_SETTING);
final Slice slice = SliceBuilderUtils.buildSlice(mContext, data);
final SliceMetadata metadata = SliceMetadata.from(mContext, slice);
assertThat(metadata.getSubtitle()).isEqualTo(
mContext.getString(R.string.disabled_dependent_setting_summary));
}
private SliceData getDummyData() { private SliceData getDummyData() {
return getDummyData(TOGGLE_CONTROLLER, SUMMARY, SliceData.SliceType.SWITCH, SCREEN_TITLE, return getDummyData(TOGGLE_CONTROLLER, SUMMARY, SliceData.SliceType.SWITCH, SCREEN_TITLE,
ICON, IS_DYNAMIC_SUMMARY_ALLOWED); ICON, IS_DYNAMIC_SUMMARY_ALLOWED, null /* unavailableSliceSubtitle */);
} }
private SliceData getDummyData(boolean isDynamicSummaryAllowed) { private SliceData getDummyData(boolean isDynamicSummaryAllowed) {
return getDummyData(TOGGLE_CONTROLLER, SUMMARY, SliceData.SliceType.SWITCH, SCREEN_TITLE, return getDummyData(TOGGLE_CONTROLLER, SUMMARY, SliceData.SliceType.SWITCH, SCREEN_TITLE,
ICON, isDynamicSummaryAllowed); ICON, isDynamicSummaryAllowed, null /* unavailableSliceSubtitle */);
} }
private SliceData getDummyData(Class prefController, int sliceType, int icon) { private SliceData getDummyData(Class prefController, int sliceType, int icon) {
return getDummyData(TOGGLE_CONTROLLER, SUMMARY, SliceData.SliceType.SWITCH, SCREEN_TITLE, return getDummyData(prefController, SUMMARY, sliceType, SCREEN_TITLE,
icon, IS_DYNAMIC_SUMMARY_ALLOWED); icon, IS_DYNAMIC_SUMMARY_ALLOWED, null /* unavailableSliceSubtitle */);
} }
private SliceData getDummyData(String summary, String screenTitle) { private SliceData getDummyData(String summary, String screenTitle) {
return getDummyData(TOGGLE_CONTROLLER, summary, SliceData.SliceType.SWITCH, screenTitle, return getDummyData(TOGGLE_CONTROLLER, summary, SliceData.SliceType.SWITCH, screenTitle,
ICON, IS_DYNAMIC_SUMMARY_ALLOWED); ICON, IS_DYNAMIC_SUMMARY_ALLOWED, null /* unavailableSliceSubtitle */);
} }
private SliceData getDummyData(Class prefController, int sliceType) { private SliceData getDummyData(Class prefController, int sliceType) {
return getDummyData(prefController, SUMMARY, sliceType, SCREEN_TITLE, ICON, return getDummyData(prefController, SUMMARY, sliceType, SCREEN_TITLE, ICON,
IS_DYNAMIC_SUMMARY_ALLOWED); IS_DYNAMIC_SUMMARY_ALLOWED, null /* unavailableSliceSubtitle */);
} }
private SliceData getDummyData(Class prefController, String summary, int sliceType, private SliceData getDummyData(Class prefController, String summary, int sliceType,
String screenTitle, int icon, boolean isDynamicSummaryAllowed) { String screenTitle, int icon, boolean isDynamicSummaryAllowed,
String unavailableSliceSubtitle) {
return new SliceData.Builder() return new SliceData.Builder()
.setKey(KEY) .setKey(KEY)
.setTitle(TITLE) .setTitle(TITLE)
@@ -557,6 +589,7 @@ public class SliceBuilderUtilsTest {
.setPreferenceControllerClassName(prefController.getName()) .setPreferenceControllerClassName(prefController.getName())
.setSliceType(sliceType) .setSliceType(sliceType)
.setDynamicSummaryAllowed(isDynamicSummaryAllowed) .setDynamicSummaryAllowed(isDynamicSummaryAllowed)
.setUnavailableSliceSubtitle(unavailableSliceSubtitle)
.build(); .build();
} }
} }

View File

@@ -125,6 +125,8 @@ public class SliceDataConverterTest {
assertThat(fakeSlice.getSliceType()).isEqualTo(SliceData.SliceType.SLIDER); assertThat(fakeSlice.getSliceType()).isEqualTo(SliceData.SliceType.SLIDER);
assertThat(fakeSlice.isPlatformDefined()).isTrue(); // from XML assertThat(fakeSlice.isPlatformDefined()).isTrue(); // from XML
assertThat(fakeSlice.isDynamicSummaryAllowed()).isTrue(); // from XML assertThat(fakeSlice.isDynamicSummaryAllowed()).isTrue(); // from XML
assertThat(fakeSlice.getUnavailableSliceSubtitle()).isEqualTo(
"subtitleOfUnavailableSlice"); // from XML
} }
private void assertFakeA11ySlice(SliceData fakeSlice) { private void assertFakeA11ySlice(SliceData fakeSlice) {

View File

@@ -39,6 +39,7 @@ public class SliceDataTest {
private final int SLICE_TYPE = SliceData.SliceType.SWITCH; private final int SLICE_TYPE = SliceData.SliceType.SWITCH;
private final boolean IS_PLATFORM_DEFINED = true; private final boolean IS_PLATFORM_DEFINED = true;
private final boolean IS_DYNAMIC_SUMMARY_ALLOWED = true; private final boolean IS_DYNAMIC_SUMMARY_ALLOWED = true;
private final String UNAVAILABLE_SLICE_SUBTITLE = "subtitleOfUnavailableSlice";
@Test @Test
public void testBuilder_buildsMatchingObject() { public void testBuilder_buildsMatchingObject() {
@@ -54,7 +55,8 @@ public class SliceDataTest {
.setPreferenceControllerClassName(PREF_CONTROLLER) .setPreferenceControllerClassName(PREF_CONTROLLER)
.setSliceType(SLICE_TYPE) .setSliceType(SLICE_TYPE)
.setPlatformDefined(IS_PLATFORM_DEFINED) .setPlatformDefined(IS_PLATFORM_DEFINED)
.setDynamicSummaryAllowed(IS_DYNAMIC_SUMMARY_ALLOWED); .setDynamicSummaryAllowed(IS_DYNAMIC_SUMMARY_ALLOWED)
.setUnavailableSliceSubtitle(UNAVAILABLE_SLICE_SUBTITLE);
SliceData data = builder.build(); SliceData data = builder.build();
@@ -70,6 +72,7 @@ public class SliceDataTest {
assertThat(data.getSliceType()).isEqualTo(SLICE_TYPE); assertThat(data.getSliceType()).isEqualTo(SLICE_TYPE);
assertThat(data.isPlatformDefined()).isEqualTo(IS_PLATFORM_DEFINED); assertThat(data.isPlatformDefined()).isEqualTo(IS_PLATFORM_DEFINED);
assertThat(data.isDynamicSummaryAllowed()).isEqualTo(IS_DYNAMIC_SUMMARY_ALLOWED); assertThat(data.isDynamicSummaryAllowed()).isEqualTo(IS_DYNAMIC_SUMMARY_ALLOWED);
assertThat(data.getUnavailableSliceSubtitle()).isEqualTo(UNAVAILABLE_SLICE_SUBTITLE);
} }
@Test(expected = SliceData.InvalidSliceDataException.class) @Test(expected = SliceData.InvalidSliceDataException.class)

View File

@@ -109,12 +109,14 @@ public class SlicesDatabaseAccessorTest {
assertThat(data.getUri()).isNull(); assertThat(data.getUri()).isNull();
assertThat(data.getPreferenceController()).isEqualTo(FAKE_CONTROLLER_NAME); assertThat(data.getPreferenceController()).isEqualTo(FAKE_CONTROLLER_NAME);
assertThat(data.isDynamicSummaryAllowed()).isFalse(); /* default value */ assertThat(data.isDynamicSummaryAllowed()).isFalse(); /* default value */
assertThat(data.getUnavailableSliceSubtitle()).isNull();
} }
@Test @Test
public void testGetSliceDataFromKey_allowDynamicSummary_validSliceReturned() { public void testGetSliceDataFromKey_allowDynamicSummary_validSliceReturned() {
String key = "key"; String key = "key";
insertSpecialCase(key, true /* isPlatformSlice */, true /* isDynamicSummaryAllowed */); insertSpecialCase(key, true /* isPlatformSlice */, true /* isDynamicSummaryAllowed */,
null /* customizedUnavailableSliceSubtitle */);
SliceData data = mAccessor.getSliceDataFromKey(key); SliceData data = mAccessor.getSliceDataFromKey(key);
@@ -133,7 +135,8 @@ public class SlicesDatabaseAccessorTest {
@Test @Test
public void testGetSliceDataFromKey_doNotAllowDynamicSummary_validSliceReturned() { public void testGetSliceDataFromKey_doNotAllowDynamicSummary_validSliceReturned() {
String key = "key"; String key = "key";
insertSpecialCase(key, true /* isPlatformSlice */, false /* isDynamicSummaryAllowed */); insertSpecialCase(key, true /* isPlatformSlice */, false /* isDynamicSummaryAllowed */,
null /* customizedUnavailableSliceSubtitle */);
SliceData data = mAccessor.getSliceDataFromKey(key); SliceData data = mAccessor.getSliceDataFromKey(key);
@@ -243,16 +246,58 @@ public class SlicesDatabaseAccessorTest {
assertThat(keys).isNotEmpty(); assertThat(keys).isNotEmpty();
} }
@Test
public void testGetSliceDataFromKey_defaultUnavailableSlice_validSliceReturned() {
String key = "key";
insertSpecialCase(key, true /* isPlatformSlice */, true /* isDynamicSummaryAllowed */,
null /* customizedUnavailableSliceSubtitle */);
SliceData data = mAccessor.getSliceDataFromKey(key);
assertThat(data.getKey()).isEqualTo(key);
assertThat(data.getTitle()).isEqualTo(FAKE_TITLE);
assertThat(data.getSummary()).isEqualTo(FAKE_SUMMARY);
assertThat(data.getScreenTitle()).isEqualTo(FAKE_SCREEN_TITLE);
assertThat(data.getKeywords()).isEqualTo(FAKE_KEYWORDS);
assertThat(data.getIconResource()).isEqualTo(FAKE_ICON);
assertThat(data.getFragmentClassName()).isEqualTo(FAKE_FRAGMENT_NAME);
assertThat(data.getUri()).isNull();
assertThat(data.getPreferenceController()).isEqualTo(FAKE_CONTROLLER_NAME);
assertThat(data.getUnavailableSliceSubtitle()).isNull();
}
@Test
public void testGetSliceDataFromKey_customizeSubtitleOfUnavailableSlice_validSliceReturned() {
String key = "key";
String subtitle = "subtitle";
insertSpecialCase(key, true /* isPlatformSlice */, true /* isDynamicSummaryAllowed */,
subtitle);
SliceData data = mAccessor.getSliceDataFromKey(key);
assertThat(data.getKey()).isEqualTo(key);
assertThat(data.getTitle()).isEqualTo(FAKE_TITLE);
assertThat(data.getSummary()).isEqualTo(FAKE_SUMMARY);
assertThat(data.getScreenTitle()).isEqualTo(FAKE_SCREEN_TITLE);
assertThat(data.getKeywords()).isEqualTo(FAKE_KEYWORDS);
assertThat(data.getIconResource()).isEqualTo(FAKE_ICON);
assertThat(data.getFragmentClassName()).isEqualTo(FAKE_FRAGMENT_NAME);
assertThat(data.getUri()).isNull();
assertThat(data.getPreferenceController()).isEqualTo(FAKE_CONTROLLER_NAME);
assertThat(data.getUnavailableSliceSubtitle()).isEqualTo(subtitle);
}
private void insertSpecialCase(String key) { private void insertSpecialCase(String key) {
insertSpecialCase(key, true); insertSpecialCase(key, true);
} }
private void insertSpecialCase(String key, boolean isPlatformSlice) { private void insertSpecialCase(String key, boolean isPlatformSlice) {
insertSpecialCase(key, isPlatformSlice, false /* isDynamicSummaryAllowed */); insertSpecialCase(key, isPlatformSlice, false /* isDynamicSummaryAllowed */,
null /*customizedUnavailableSliceSubtitle*/);
} }
private void insertSpecialCase(String key, boolean isPlatformSlice, private void insertSpecialCase(String key, boolean isPlatformSlice,
boolean isDynamicSummaryAllowed) { boolean isDynamicSummaryAllowed, String customizedUnavailableSliceSubtitle) {
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
values.put(SlicesDatabaseHelper.IndexColumns.KEY, key); values.put(SlicesDatabaseHelper.IndexColumns.KEY, key);
values.put(SlicesDatabaseHelper.IndexColumns.TITLE, FAKE_TITLE); values.put(SlicesDatabaseHelper.IndexColumns.TITLE, FAKE_TITLE);
@@ -266,6 +311,8 @@ public class SlicesDatabaseAccessorTest {
values.put(SlicesDatabaseHelper.IndexColumns.ALLOW_DYNAMIC_SUMMARY_IN_SLICE, values.put(SlicesDatabaseHelper.IndexColumns.ALLOW_DYNAMIC_SUMMARY_IN_SLICE,
isDynamicSummaryAllowed); isDynamicSummaryAllowed);
values.put(SlicesDatabaseHelper.IndexColumns.SLICE_TYPE, SliceData.SliceType.INTENT); values.put(SlicesDatabaseHelper.IndexColumns.SLICE_TYPE, SliceData.SliceType.INTENT);
values.put(SlicesDatabaseHelper.IndexColumns.UNAVAILABLE_SLICE_SUBTITLE,
customizedUnavailableSliceSubtitle);
mDb.replaceOrThrow(SlicesDatabaseHelper.Tables.TABLE_SLICES_INDEX, null, values); mDb.replaceOrThrow(SlicesDatabaseHelper.Tables.TABLE_SLICES_INDEX, null, values);
} }

View File

@@ -74,6 +74,7 @@ public class SlicesDatabaseHelperTest {
IndexColumns.PLATFORM_SLICE, IndexColumns.PLATFORM_SLICE,
IndexColumns.SLICE_TYPE, IndexColumns.SLICE_TYPE,
IndexColumns.ALLOW_DYNAMIC_SUMMARY_IN_SLICE, IndexColumns.ALLOW_DYNAMIC_SUMMARY_IN_SLICE,
IndexColumns.UNAVAILABLE_SLICE_SUBTITLE,
}; };
assertThat(columnNames).isEqualTo(expectedNames); assertThat(columnNames).isEqualTo(expectedNames);

View File

@@ -55,6 +55,7 @@ public class SlicesIndexerTest {
private final boolean PLATFORM_DEFINED = true; private final boolean PLATFORM_DEFINED = true;
private final boolean IS_DYNAMIC_SUMMARY_ALLOWED = true; private final boolean IS_DYNAMIC_SUMMARY_ALLOWED = true;
private final int SLICE_TYPE = SliceData.SliceType.SLIDER; private final int SLICE_TYPE = SliceData.SliceType.SLIDER;
private final String UNAVAILABLE_SLICE_SUBTITLE = "subtitleOfUnavailableSlice";
private Context mContext; private Context mContext;
@@ -145,6 +146,9 @@ public class SlicesIndexerTest {
cursor.getColumnIndex( cursor.getColumnIndex(
IndexColumns.ALLOW_DYNAMIC_SUMMARY_IN_SLICE))) IndexColumns.ALLOW_DYNAMIC_SUMMARY_IN_SLICE)))
.isEqualTo(1 /* true */); .isEqualTo(1 /* true */);
assertThat(cursor.getString(
cursor.getColumnIndex(IndexColumns.UNAVAILABLE_SLICE_SUBTITLE)))
.isEqualTo(UNAVAILABLE_SLICE_SUBTITLE);
cursor.moveToNext(); cursor.moveToNext();
} }
} finally { } finally {
@@ -179,7 +183,8 @@ public class SlicesIndexerTest {
.setPreferenceControllerClassName(PREF_CONTROLLER) .setPreferenceControllerClassName(PREF_CONTROLLER)
.setPlatformDefined(PLATFORM_DEFINED) .setPlatformDefined(PLATFORM_DEFINED)
.setSliceType(SLICE_TYPE) .setSliceType(SLICE_TYPE)
.setDynamicSummaryAllowed(IS_DYNAMIC_SUMMARY_ALLOWED); .setDynamicSummaryAllowed(IS_DYNAMIC_SUMMARY_ALLOWED)
.setUnavailableSliceSubtitle(UNAVAILABLE_SLICE_SUBTITLE);
for (int i = 0; i < KEYS.length; i++) { for (int i = 0; i < KEYS.length; i++) {
builder.setKey(KEYS[i]).setTitle(TITLES[i]); builder.setKey(KEYS[i]).setTitle(TITLES[i]);