Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 82254b08 authored by Matthew Fritze's avatar Matthew Fritze
Browse files

Add dynamic summaries to Slices

Summary on slices will now determined by checking that
summaries in the following order are valid:
1) SliceData summary
2) Preference Controller summary
3) SliceData screen title

Valid is currently defined as:
- Not empty / null
- Not whitespace
- Not sumamry placeholder

Fixes: 71640678
Test: robotests
Change-Id: I5e699e8566ece80742d311617b7dc4e9a9bda8cf
parent 84414568
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -71,7 +71,7 @@ public class SliceBroadcastReceiver extends BroadcastReceiver {
            throw new IllegalStateException("No key passed to Intent for toggle controller");
        }

        BasePreferenceController controller = getBasePreferenceController(context, key);
        final BasePreferenceController controller = getPreferenceController(context, key);

        if (!(controller instanceof TogglePreferenceController)) {
            throw new IllegalStateException("Toggle action passed for a non-toggle key: " + key);
@@ -79,12 +79,12 @@ public class SliceBroadcastReceiver extends BroadcastReceiver {

        // TODO post context.getContentResolver().notifyChanged(uri, null) in the Toggle controller
        // so that it's automatically broadcast to any slice.
        TogglePreferenceController toggleController = (TogglePreferenceController) controller;
        boolean currentValue = toggleController.isChecked();
        final TogglePreferenceController toggleController = (TogglePreferenceController) controller;
        final boolean currentValue = toggleController.isChecked();
        toggleController.setChecked(!currentValue);
    }

    private BasePreferenceController getBasePreferenceController(Context context, String key) {
    private BasePreferenceController getPreferenceController(Context context, String key) {
        final SlicesDatabaseAccessor accessor = new SlicesDatabaseAccessor(context);
        final SliceData sliceData = accessor.getSliceDataFromKey(key);
        return SliceBuilderUtils.getPreferenceController(context, sliceData);
+39 −9
Original line number Diff line number Diff line
@@ -24,10 +24,13 @@ import android.content.Intent;
import android.graphics.drawable.Icon;
import android.text.TextUtils;

import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.R;
import com.android.settings.SubSettings;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.core.TogglePreferenceController;
import com.android.settings.search.DatabaseIndexingUtils;
import com.android.settingslib.core.AbstractPreferenceController;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
@@ -54,21 +57,17 @@ public class SliceBuilderUtils {
    public static Slice buildSlice(Context context, SliceData sliceData) {
        final PendingIntent contentIntent = getContentIntent(context, sliceData);
        final Icon icon = Icon.createWithResource(context, sliceData.getIconResource());
        String summaryText = sliceData.getSummary();
        String subtitleText = TextUtils.isEmpty(summaryText)
                ? sliceData.getScreenTitle()
                : summaryText;
        final BasePreferenceController controller = getPreferenceController(context, sliceData);

        final String subtitleText = getSubtitleText(context, controller, sliceData);

        RowBuilder builder = new RowBuilder(context, sliceData.getUri())
        final RowBuilder builder = new RowBuilder(context, sliceData.getUri())
                .setTitle(sliceData.getTitle())
                .setTitleItem(icon)
                .setSubtitle(subtitleText)
                .setContentIntent(contentIntent);

        BasePreferenceController controller = getPreferenceController(context, sliceData);

        // TODO (b/71640747) Respect setting availability.
        // TODO (b/71640678) Add dynamic summary text.

        if (controller instanceof TogglePreferenceController) {
            addToggleAction(context, builder, ((TogglePreferenceController) controller).isChecked(),
@@ -82,7 +81,7 @@ public class SliceBuilderUtils {

    /**
     * Looks at the {@link SliceData#preferenceController} from {@param sliceData} and attempts to
     * build a {@link BasePreferenceController}.
     * build an {@link AbstractPreferenceController}.
     */
    public static BasePreferenceController getPreferenceController(Context context,
            SliceData sliceData) {
@@ -122,4 +121,35 @@ public class SliceBuilderUtils {
        intent.setClassName("com.android.settings", SubSettings.class.getName());
        return PendingIntent.getActivity(context, 0 /* requestCode */, intent, 0 /* flags */);
    }

    @VisibleForTesting
    static String getSubtitleText(Context context, AbstractPreferenceController controller,
            SliceData sliceData) {
        String summaryText = sliceData.getSummary();
        if (isValidSummary(context, summaryText)) {
            return summaryText;
        }

        if (controller != null) {
            summaryText = controller.getSummary();

            if (isValidSummary(context, summaryText)) {
                return summaryText;
            }
        }

        return sliceData.getScreenTitle();
    }

    private static boolean isValidSummary(Context context, String summary) {
        if (summary == null || TextUtils.isEmpty(summary.trim())) {
            return false;
        }

        final String placeHolder = context.getString(R.string.summary_placeholder);
        final String doublePlaceHolder = context.getString(R.string.summary_two_lines_placeholder);

        return !(TextUtils.equals(summary, placeHolder)
                || TextUtils.equals(summary, doublePlaceHolder));
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -163,7 +163,7 @@ class SliceDataConverter {

                // 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 intens:
                // TODO (b/67996923) This will not work if preferences have nested intents:
                // <pref ....>
                //      <intent action="blab"/> </pref>
                controllerClassName = XmlParserUtils.getController(mContext, attrs);
+65 −4
Original line number Diff line number Diff line
@@ -20,9 +20,13 @@ import static com.android.settings.TestConfig.SDK_VERSION;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;

import android.content.Context;
import android.net.Uri;

import com.android.settings.R;
import com.android.settings.TestConfig;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
@@ -37,7 +41,7 @@ import androidx.app.slice.Slice;

@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = SDK_VERSION)
public class SlicesDatabaseUtilsTest {
public class SliceBuilderUtilsTest {

    private final String KEY = "KEY";
    private final String TITLE = "title";
@@ -65,17 +69,74 @@ public class SlicesDatabaseUtilsTest {

    @Test
    public void testGetPreferenceController_buildsMatchingController() {
        BasePreferenceController controller = SliceBuilderUtils.getPreferenceController(mContext,
                getDummyData());
        BasePreferenceController controller = SliceBuilderUtils.getPreferenceController(
                mContext, getDummyData());

        assertThat(controller).isInstanceOf(FakeToggleController.class);
    }

    @Test
    public void testDynamicSummary_returnsSliceSummary() {
        SliceData data = getDummyData();
        FakePreferenceController controller = new FakePreferenceController(mContext, KEY);

        String summary = SliceBuilderUtils.getSubtitleText(mContext, controller, data);

        assertThat(summary).isEqualTo(data.getSummary());
    }

    @Test
    public void testDynamicSummary_returnsFragmentSummary() {
        SliceData data = getDummyData(null);
        FakePreferenceController controller = spy(new FakePreferenceController(mContext, KEY));
        String controllerSummary = "new_Summary";
        doReturn(controllerSummary).when(controller).getSummary();

        String summary = SliceBuilderUtils.getSubtitleText(mContext, controller, data);

        assertThat(summary).isEqualTo(controllerSummary);
    }

    @Test
    public void testDynamicSummary_returnsSliceScreenTitle() {
        SliceData data = getDummyData(null);
        FakePreferenceController controller = new FakePreferenceController(mContext, KEY);

        String summary = SliceBuilderUtils.getSubtitleText(mContext, controller, data);

        assertThat(summary).isEqualTo(data.getScreenTitle());
    }

    @Test
    public void testDynamicSummary_placeHolderString_returnsScreenTitle() {
        SliceData data = getDummyData(mContext.getString(R.string.summary_placeholder));
        FakePreferenceController controller = new FakePreferenceController(mContext, KEY);
        String summary = SliceBuilderUtils.getSubtitleText(mContext, controller, data);

        assertThat(summary).isEqualTo(data.getScreenTitle());
    }

    @Test
    public void testDynamicSummary_sliceDataAndFragmentPlaceholder_returnsSliceScreenTitle() {
        String summaryPlaceholder = mContext.getString(R.string.summary_placeholder);
        SliceData data = getDummyData(summaryPlaceholder);
        FakePreferenceController controller = spy(new FakePreferenceController(mContext, KEY));
        doReturn(summaryPlaceholder).when(controller).getSummary();

        String summary = SliceBuilderUtils.getSubtitleText(mContext, controller, data);

        assertThat(summary).isEqualTo(data.getScreenTitle());
    }

    private SliceData getDummyData() {
        return getDummyData(SUMMARY);
    }

    private SliceData getDummyData(String summary) {
        return new SliceData.Builder()
                .setKey(KEY)
                .setTitle(TITLE)
                .setSummary(SUMMARY)
                .setSummary(summary)
                .setScreenTitle(SCREEN_TITLE)
                .setIcon(ICON)
                .setFragmentName(FRAGMENT_NAME)