18c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritze/*
28c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritze * Copyright (C) 2017 The Android Open Source Project
38c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritze *
48c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritze * Licensed under the Apache License, Version 2.0 (the "License");
58c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritze * you may not use this file except in compliance with the License.
68c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritze * You may obtain a copy of the License at
78c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritze *
88c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritze *      http://www.apache.org/licenses/LICENSE-2.0
98c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritze *
108c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritze * Unless required by applicable law or agreed to in writing, software
118c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritze * distributed under the License is distributed on an "AS IS" BASIS,
128c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritze * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritze * See the License for the specific language governing permissions and
148c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritze * limitations under the License
158c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritze */
168c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritze
178c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritzepackage com.android.settings.slices;
188c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritze
19dba7d1c4b3f1cc8ae48c7b86b2259377d2fe6fbcMatthew Fritzeimport static com.android.settings.core.BasePreferenceController.AVAILABLE;
20bd376296cd5b5a41c421b4d831036957915336ceMatthew Fritzeimport static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
21fcdfc2d83fe3ff4fd2e75676023cbab895941151Matthew Fritzeimport static com.android.settings.core.BasePreferenceController.DISABLED_DEPENDENT_SETTING;
22fcdfc2d83fe3ff4fd2e75676023cbab895941151Matthew Fritzeimport static com.android.settings.core.BasePreferenceController.DISABLED_FOR_USER;
23bd376296cd5b5a41c421b4d831036957915336ceMatthew Fritzeimport static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
248c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritzeimport static com.android.settings.slices.SettingsSliceProvider.EXTRA_SLICE_KEY;
25fcdfc2d83fe3ff4fd2e75676023cbab895941151Matthew Fritzeimport static com.android.settings.slices.SettingsSliceProvider.EXTRA_SLICE_PLATFORM_DEFINED;
268c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritze
277d565e97a3a56ac2f343d25e03b2a98833b7a997Matthew Fritzeimport android.annotation.ColorInt;
288c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritzeimport android.app.PendingIntent;
29a4a3dfffa20e317f4236349e4717f9da312b8ee1Matthew Fritzeimport android.content.ContentResolver;
308c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritzeimport android.content.Context;
318c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritzeimport android.content.Intent;
32a4a3dfffa20e317f4236349e4717f9da312b8ee1Matthew Fritzeimport android.net.Uri;
33c301964167145dbc0051df401f091ea946003c7bMatthew Fritzeimport android.provider.Settings;
34a4a3dfffa20e317f4236349e4717f9da312b8ee1Matthew Fritzeimport android.provider.SettingsSlicesContract;
358c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritzeimport android.text.TextUtils;
36c301964167145dbc0051df401f091ea946003c7bMatthew Fritzeimport android.util.Log;
3779c6395295fa2361901ed94bd5ee035418626d81Matthew Fritzeimport android.util.Pair;
388c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritze
3982254b08fd4d74c6a707fe20cec8c68a3e54b329Matthew Fritzeimport com.android.internal.annotations.VisibleForTesting;
4087b2634fc0c1c0ab8280f9af12d7cdbd00375480Fan Zhangimport com.android.internal.logging.nano.MetricsProto.MetricsEvent;
4182254b08fd4d74c6a707fe20cec8c68a3e54b329Matthew Fritzeimport com.android.settings.R;
428c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritzeimport com.android.settings.SubSettings;
437d565e97a3a56ac2f343d25e03b2a98833b7a997Matthew Fritzeimport com.android.settings.Utils;
448c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritzeimport com.android.settings.core.BasePreferenceController;
45ad6678f9fc08b26bdcbe26e8394551b9c5fb0457Matthew Fritzeimport com.android.settings.core.SliderPreferenceController;
468c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritzeimport com.android.settings.core.TogglePreferenceController;
4787b2634fc0c1c0ab8280f9af12d7cdbd00375480Fan Zhangimport com.android.settings.overlay.FeatureFactory;
488c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritzeimport com.android.settings.search.DatabaseIndexingUtils;
4946aa5866108e9b50d133977f8877d2456960ee6aMatthew Fritzeimport com.android.settingslib.SliceBroadcastRelay;
5082254b08fd4d74c6a707fe20cec8c68a3e54b329Matthew Fritzeimport com.android.settingslib.core.AbstractPreferenceController;
518c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritze
5220210122bd7eb16426b7633f5f7fa9ccf1ad3de8Jason Monkimport android.support.v4.graphics.drawable.IconCompat;
53dba7d1c4b3f1cc8ae48c7b86b2259377d2fe6fbcMatthew Fritze
5447a44e8fa4974193d692cc1d86201b18ba7adbfeMatthew Fritzeimport java.util.ArrayList;
5547a44e8fa4974193d692cc1d86201b18ba7adbfeMatthew Fritzeimport java.util.Arrays;
5647a44e8fa4974193d692cc1d86201b18ba7adbfeMatthew Fritzeimport java.util.List;
5746aa5866108e9b50d133977f8877d2456960ee6aMatthew Fritzeimport java.util.stream.Collectors;
5847a44e8fa4974193d692cc1d86201b18ba7adbfeMatthew Fritze
594734b3448aadad5cd36d48efb50b4b8051f75184Alan Viveretteimport androidx.slice.Slice;
604734b3448aadad5cd36d48efb50b4b8051f75184Alan Viveretteimport androidx.slice.builders.ListBuilder;
6187b2634fc0c1c0ab8280f9af12d7cdbd00375480Fan Zhangimport androidx.slice.builders.SliceAction;
628c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritze
63ad6678f9fc08b26bdcbe26e8394551b9c5fb0457Matthew Fritze
648c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritze/**
658c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritze * Utility class to build Slices objects and Preference Controllers based on the Database managed
668c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritze * by {@link SlicesDatabaseHelper}
678c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritze */
688c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritzepublic class SliceBuilderUtils {
698c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritze
708c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritze    private static final String TAG = "SliceBuilder";
718c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritze
728c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritze    /**
738c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritze     * Build a Slice from {@link SliceData}.
748c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritze     *
758c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritze     * @return a {@link Slice} based on the data provided by {@param sliceData}.
768c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritze     * Will build an {@link Intent} based Slice unless the Preference Controller name in
778c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritze     * {@param sliceData} is an inline controller.
788c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritze     */
798c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritze    public static Slice buildSlice(Context context, SliceData sliceData) {
80c301964167145dbc0051df401f091ea946003c7bMatthew Fritze        Log.d(TAG, "Creating slice for: " + sliceData.getPreferenceController());
81ad6678f9fc08b26bdcbe26e8394551b9c5fb0457Matthew Fritze        final BasePreferenceController controller = getPreferenceController(context, sliceData);
8287b2634fc0c1c0ab8280f9af12d7cdbd00375480Fan Zhang        final Pair<Integer, Object> sliceNamePair =
8387b2634fc0c1c0ab8280f9af12d7cdbd00375480Fan Zhang                Pair.create(MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_NAME, sliceData.getKey());
8487b2634fc0c1c0ab8280f9af12d7cdbd00375480Fan Zhang        // Log Slice requests using the same schema as SharedPreferenceLogger (but with a different
8587b2634fc0c1c0ab8280f9af12d7cdbd00375480Fan Zhang        // action name).
8687b2634fc0c1c0ab8280f9af12d7cdbd00375480Fan Zhang        FeatureFactory.getFactory(context).getMetricsFeatureProvider()
8787b2634fc0c1c0ab8280f9af12d7cdbd00375480Fan Zhang                .action(context, MetricsEvent.ACTION_SETTINGS_SLICE_REQUESTED, sliceNamePair);
88dba7d1c4b3f1cc8ae48c7b86b2259377d2fe6fbcMatthew Fritze
89d9613b2742bdb8441b8050edfdf0a9772f7d45c9Matthew Fritze        if (!controller.isAvailable()) {
90d9613b2742bdb8441b8050edfdf0a9772f7d45c9Matthew Fritze            // Cannot guarantee setting page is accessible, let the presenter handle error case.
91d9613b2742bdb8441b8050edfdf0a9772f7d45c9Matthew Fritze            return null;
92d9613b2742bdb8441b8050edfdf0a9772f7d45c9Matthew Fritze        }
93d9613b2742bdb8441b8050edfdf0a9772f7d45c9Matthew Fritze
94d9613b2742bdb8441b8050edfdf0a9772f7d45c9Matthew Fritze        if (controller.getAvailabilityStatus() == DISABLED_DEPENDENT_SETTING) {
95d9613b2742bdb8441b8050edfdf0a9772f7d45c9Matthew Fritze            return buildUnavailableSlice(context, sliceData);
96fcdfc2d83fe3ff4fd2e75676023cbab895941151Matthew Fritze        }
97fcdfc2d83fe3ff4fd2e75676023cbab895941151Matthew Fritze
98ad6678f9fc08b26bdcbe26e8394551b9c5fb0457Matthew Fritze        switch (sliceData.getSliceType()) {
99ad6678f9fc08b26bdcbe26e8394551b9c5fb0457Matthew Fritze            case SliceData.SliceType.INTENT:
100ad6678f9fc08b26bdcbe26e8394551b9c5fb0457Matthew Fritze                return buildIntentSlice(context, sliceData, controller);
101ad6678f9fc08b26bdcbe26e8394551b9c5fb0457Matthew Fritze            case SliceData.SliceType.SWITCH:
102ad6678f9fc08b26bdcbe26e8394551b9c5fb0457Matthew Fritze                return buildToggleSlice(context, sliceData, controller);
103ad6678f9fc08b26bdcbe26e8394551b9c5fb0457Matthew Fritze            case SliceData.SliceType.SLIDER:
104ad6678f9fc08b26bdcbe26e8394551b9c5fb0457Matthew Fritze                return buildSliderSlice(context, sliceData, controller);
105ad6678f9fc08b26bdcbe26e8394551b9c5fb0457Matthew Fritze            default:
106ad6678f9fc08b26bdcbe26e8394551b9c5fb0457Matthew Fritze                throw new IllegalArgumentException(
107ad6678f9fc08b26bdcbe26e8394551b9c5fb0457Matthew Fritze                        "Slice type passed was invalid: " + sliceData.getSliceType());
1088c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritze        }
1098c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritze    }
1108c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritze
1118c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritze    /**
1121e9d9c7054270f92b4b7db4d3f405cb9ed38c051Matthew Fritze     * @return the {@link SliceData.SliceType} for the {@param controllerClassName} and key.
1131e9d9c7054270f92b4b7db4d3f405cb9ed38c051Matthew Fritze     */
1141e9d9c7054270f92b4b7db4d3f405cb9ed38c051Matthew Fritze    @SliceData.SliceType
1151e9d9c7054270f92b4b7db4d3f405cb9ed38c051Matthew Fritze    public static int getSliceType(Context context, String controllerClassName,
1161e9d9c7054270f92b4b7db4d3f405cb9ed38c051Matthew Fritze            String controllerKey) {
1171e9d9c7054270f92b4b7db4d3f405cb9ed38c051Matthew Fritze        BasePreferenceController controller = getPreferenceController(context, controllerClassName,
1181e9d9c7054270f92b4b7db4d3f405cb9ed38c051Matthew Fritze                controllerKey);
1191e9d9c7054270f92b4b7db4d3f405cb9ed38c051Matthew Fritze        return controller.getSliceType();
1201e9d9c7054270f92b4b7db4d3f405cb9ed38c051Matthew Fritze    }
1211e9d9c7054270f92b4b7db4d3f405cb9ed38c051Matthew Fritze
1221e9d9c7054270f92b4b7db4d3f405cb9ed38c051Matthew Fritze    /**
12379c6395295fa2361901ed94bd5ee035418626d81Matthew Fritze     * Splits the Settings Slice Uri path into its two expected components:
12479c6395295fa2361901ed94bd5ee035418626d81Matthew Fritze     * - intent/action
12579c6395295fa2361901ed94bd5ee035418626d81Matthew Fritze     * - key
12679c6395295fa2361901ed94bd5ee035418626d81Matthew Fritze     * <p>
12779c6395295fa2361901ed94bd5ee035418626d81Matthew Fritze     * Examples of valid paths are:
128a711ed833099de30f589733cbb2c9b03a19097a6Matthew Fritze     * - /intent/wifi
129a711ed833099de30f589733cbb2c9b03a19097a6Matthew Fritze     * - /intent/bluetooth
130a711ed833099de30f589733cbb2c9b03a19097a6Matthew Fritze     * - /action/wifi
131a711ed833099de30f589733cbb2c9b03a19097a6Matthew Fritze     * - /action/accessibility/servicename
13279c6395295fa2361901ed94bd5ee035418626d81Matthew Fritze     *
13379c6395295fa2361901ed94bd5ee035418626d81Matthew Fritze     * @param uri of the Slice. Follows pattern outlined in {@link SettingsSliceProvider}.
134a711ed833099de30f589733cbb2c9b03a19097a6Matthew Fritze     * @return Pair whose first element {@code true} if the path is prepended with "intent", and
13579c6395295fa2361901ed94bd5ee035418626d81Matthew Fritze     * second is a key.
13679c6395295fa2361901ed94bd5ee035418626d81Matthew Fritze     */
13779c6395295fa2361901ed94bd5ee035418626d81Matthew Fritze    public static Pair<Boolean, String> getPathData(Uri uri) {
13879c6395295fa2361901ed94bd5ee035418626d81Matthew Fritze        final String path = uri.getPath();
13979c6395295fa2361901ed94bd5ee035418626d81Matthew Fritze        final String[] split = path.split("/", 3);
14079c6395295fa2361901ed94bd5ee035418626d81Matthew Fritze
14179c6395295fa2361901ed94bd5ee035418626d81Matthew Fritze        // Split should be: [{}, SLICE_TYPE, KEY].
14279c6395295fa2361901ed94bd5ee035418626d81Matthew Fritze        // Example: "/action/wifi" -> [{}, "action", "wifi"]
14379c6395295fa2361901ed94bd5ee035418626d81Matthew Fritze        //          "/action/longer/path" -> [{}, "action", "longer/path"]
14479c6395295fa2361901ed94bd5ee035418626d81Matthew Fritze        if (split.length != 3) {
1456730a061b1c297eca8f38ab3cfff620da10cbdb3Matthew Fritze            return null;
14679c6395295fa2361901ed94bd5ee035418626d81Matthew Fritze        }
14779c6395295fa2361901ed94bd5ee035418626d81Matthew Fritze
148a711ed833099de30f589733cbb2c9b03a19097a6Matthew Fritze        final boolean isIntent = TextUtils.equals(SettingsSlicesContract.PATH_SETTING_INTENT,
14979c6395295fa2361901ed94bd5ee035418626d81Matthew Fritze                split[1]);
15079c6395295fa2361901ed94bd5ee035418626d81Matthew Fritze
151a711ed833099de30f589733cbb2c9b03a19097a6Matthew Fritze        return new Pair<>(isIntent, split[2]);
15279c6395295fa2361901ed94bd5ee035418626d81Matthew Fritze    }
15379c6395295fa2361901ed94bd5ee035418626d81Matthew Fritze
15479c6395295fa2361901ed94bd5ee035418626d81Matthew Fritze    /**
155fcdfc2d83fe3ff4fd2e75676023cbab895941151Matthew Fritze     * Looks at the controller classname in in {@link SliceData} from {@param sliceData}
156fcdfc2d83fe3ff4fd2e75676023cbab895941151Matthew Fritze     * and attempts to build an {@link AbstractPreferenceController}.
1578c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritze     */
1588c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritze    public static BasePreferenceController getPreferenceController(Context context,
1598c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritze            SliceData sliceData) {
1601e9d9c7054270f92b4b7db4d3f405cb9ed38c051Matthew Fritze        return getPreferenceController(context, sliceData.getPreferenceController(),
1611e9d9c7054270f92b4b7db4d3f405cb9ed38c051Matthew Fritze                sliceData.getKey());
1621e9d9c7054270f92b4b7db4d3f405cb9ed38c051Matthew Fritze    }
1631e9d9c7054270f92b4b7db4d3f405cb9ed38c051Matthew Fritze
164dba7d1c4b3f1cc8ae48c7b86b2259377d2fe6fbcMatthew Fritze    /**
165dba7d1c4b3f1cc8ae48c7b86b2259377d2fe6fbcMatthew Fritze     * @return {@link PendingIntent} for a non-primary {@link SliceAction}.
166dba7d1c4b3f1cc8ae48c7b86b2259377d2fe6fbcMatthew Fritze     */
167dba7d1c4b3f1cc8ae48c7b86b2259377d2fe6fbcMatthew Fritze    public static PendingIntent getActionIntent(Context context, String action, SliceData data) {
16859e2d1fff968696aef3ea6e4944a8855e22de0feMatthew Fritze        final Intent intent = new Intent(action);
169dba7d1c4b3f1cc8ae48c7b86b2259377d2fe6fbcMatthew Fritze        intent.setClass(context, SliceBroadcastReceiver.class);
170dba7d1c4b3f1cc8ae48c7b86b2259377d2fe6fbcMatthew Fritze        intent.putExtra(EXTRA_SLICE_KEY, data.getKey());
171dba7d1c4b3f1cc8ae48c7b86b2259377d2fe6fbcMatthew Fritze        intent.putExtra(EXTRA_SLICE_PLATFORM_DEFINED, data.isPlatformDefined());
172dba7d1c4b3f1cc8ae48c7b86b2259377d2fe6fbcMatthew Fritze        return PendingIntent.getBroadcast(context, 0 /* requestCode */, intent,
173dba7d1c4b3f1cc8ae48c7b86b2259377d2fe6fbcMatthew Fritze                PendingIntent.FLAG_CANCEL_CURRENT);
174dba7d1c4b3f1cc8ae48c7b86b2259377d2fe6fbcMatthew Fritze    }
175dba7d1c4b3f1cc8ae48c7b86b2259377d2fe6fbcMatthew Fritze
176dba7d1c4b3f1cc8ae48c7b86b2259377d2fe6fbcMatthew Fritze    /**
177dba7d1c4b3f1cc8ae48c7b86b2259377d2fe6fbcMatthew Fritze     * @return {@link PendingIntent} for the primary {@link SliceAction}.
178dba7d1c4b3f1cc8ae48c7b86b2259377d2fe6fbcMatthew Fritze     */
17959e2d1fff968696aef3ea6e4944a8855e22de0feMatthew Fritze    public static PendingIntent getContentPendingIntent(Context context, SliceData sliceData) {
18059e2d1fff968696aef3ea6e4944a8855e22de0feMatthew Fritze        final Intent intent = getContentIntent(context, sliceData);
181dba7d1c4b3f1cc8ae48c7b86b2259377d2fe6fbcMatthew Fritze        return PendingIntent.getActivity(context, 0 /* requestCode */, intent, 0 /* flags */);
182dba7d1c4b3f1cc8ae48c7b86b2259377d2fe6fbcMatthew Fritze    }
183dba7d1c4b3f1cc8ae48c7b86b2259377d2fe6fbcMatthew Fritze
184dba7d1c4b3f1cc8ae48c7b86b2259377d2fe6fbcMatthew Fritze    /**
185dba7d1c4b3f1cc8ae48c7b86b2259377d2fe6fbcMatthew Fritze     * @return the summary text for a {@link Slice} built for {@param sliceData}.
186dba7d1c4b3f1cc8ae48c7b86b2259377d2fe6fbcMatthew Fritze     */
187dba7d1c4b3f1cc8ae48c7b86b2259377d2fe6fbcMatthew Fritze    public static CharSequence getSubtitleText(Context context,
188dba7d1c4b3f1cc8ae48c7b86b2259377d2fe6fbcMatthew Fritze            AbstractPreferenceController controller, SliceData sliceData) {
189f9c13fc305fc2139db6df04a6596a1f5ff77ba4dMatthew Fritze        CharSequence summaryText = sliceData.getScreenTitle();
190f9c13fc305fc2139db6df04a6596a1f5ff77ba4dMatthew Fritze        if (isValidSummary(context, summaryText) && !TextUtils.equals(summaryText,
191f9c13fc305fc2139db6df04a6596a1f5ff77ba4dMatthew Fritze                sliceData.getTitle())) {
192f9c13fc305fc2139db6df04a6596a1f5ff77ba4dMatthew Fritze            return summaryText;
193f9c13fc305fc2139db6df04a6596a1f5ff77ba4dMatthew Fritze        }
194f9c13fc305fc2139db6df04a6596a1f5ff77ba4dMatthew Fritze
195dba7d1c4b3f1cc8ae48c7b86b2259377d2fe6fbcMatthew Fritze        if (controller != null) {
196dba7d1c4b3f1cc8ae48c7b86b2259377d2fe6fbcMatthew Fritze            summaryText = controller.getSummary();
197dba7d1c4b3f1cc8ae48c7b86b2259377d2fe6fbcMatthew Fritze
198dba7d1c4b3f1cc8ae48c7b86b2259377d2fe6fbcMatthew Fritze            if (isValidSummary(context, summaryText)) {
199dba7d1c4b3f1cc8ae48c7b86b2259377d2fe6fbcMatthew Fritze                return summaryText;
200dba7d1c4b3f1cc8ae48c7b86b2259377d2fe6fbcMatthew Fritze            }
201dba7d1c4b3f1cc8ae48c7b86b2259377d2fe6fbcMatthew Fritze        }
202dba7d1c4b3f1cc8ae48c7b86b2259377d2fe6fbcMatthew Fritze
203dba7d1c4b3f1cc8ae48c7b86b2259377d2fe6fbcMatthew Fritze        summaryText = sliceData.getSummary();
204dba7d1c4b3f1cc8ae48c7b86b2259377d2fe6fbcMatthew Fritze        if (isValidSummary(context, summaryText)) {
205dba7d1c4b3f1cc8ae48c7b86b2259377d2fe6fbcMatthew Fritze            return summaryText;
206dba7d1c4b3f1cc8ae48c7b86b2259377d2fe6fbcMatthew Fritze        }
207dba7d1c4b3f1cc8ae48c7b86b2259377d2fe6fbcMatthew Fritze
208dba7d1c4b3f1cc8ae48c7b86b2259377d2fe6fbcMatthew Fritze        return "";
209dba7d1c4b3f1cc8ae48c7b86b2259377d2fe6fbcMatthew Fritze    }
210dba7d1c4b3f1cc8ae48c7b86b2259377d2fe6fbcMatthew Fritze
211a4a3dfffa20e317f4236349e4717f9da312b8ee1Matthew Fritze    public static Uri getUri(String path, boolean isPlatformSlice) {
212a4a3dfffa20e317f4236349e4717f9da312b8ee1Matthew Fritze        final String authority = isPlatformSlice
213a4a3dfffa20e317f4236349e4717f9da312b8ee1Matthew Fritze                ? SettingsSlicesContract.AUTHORITY
214a4a3dfffa20e317f4236349e4717f9da312b8ee1Matthew Fritze                : SettingsSliceProvider.SLICE_AUTHORITY;
215a4a3dfffa20e317f4236349e4717f9da312b8ee1Matthew Fritze        return new Uri.Builder()
216a4a3dfffa20e317f4236349e4717f9da312b8ee1Matthew Fritze                .scheme(ContentResolver.SCHEME_CONTENT)
217a4a3dfffa20e317f4236349e4717f9da312b8ee1Matthew Fritze                .authority(authority)
218a4a3dfffa20e317f4236349e4717f9da312b8ee1Matthew Fritze                .appendPath(path)
219a4a3dfffa20e317f4236349e4717f9da312b8ee1Matthew Fritze                .build();
220a4a3dfffa20e317f4236349e4717f9da312b8ee1Matthew Fritze    }
221a4a3dfffa20e317f4236349e4717f9da312b8ee1Matthew Fritze
22259e2d1fff968696aef3ea6e4944a8855e22de0feMatthew Fritze    @VisibleForTesting
22359e2d1fff968696aef3ea6e4944a8855e22de0feMatthew Fritze    static Intent getContentIntent(Context context, SliceData sliceData) {
22459e2d1fff968696aef3ea6e4944a8855e22de0feMatthew Fritze        final Uri contentUri = new Uri.Builder().appendPath(sliceData.getKey()).build();
22559e2d1fff968696aef3ea6e4944a8855e22de0feMatthew Fritze        final Intent intent = DatabaseIndexingUtils.buildSearchResultPageIntent(context,
226a711ed833099de30f589733cbb2c9b03a19097a6Matthew Fritze                sliceData.getFragmentClassName(), sliceData.getKey(),
227a711ed833099de30f589733cbb2c9b03a19097a6Matthew Fritze                sliceData.getScreenTitle().toString(), 0 /* TODO */);
22859e2d1fff968696aef3ea6e4944a8855e22de0feMatthew Fritze        intent.setClassName(context.getPackageName(), SubSettings.class.getName());
22959e2d1fff968696aef3ea6e4944a8855e22de0feMatthew Fritze        intent.setData(contentUri);
23059e2d1fff968696aef3ea6e4944a8855e22de0feMatthew Fritze        return intent;
23159e2d1fff968696aef3ea6e4944a8855e22de0feMatthew Fritze    }
23259e2d1fff968696aef3ea6e4944a8855e22de0feMatthew Fritze
233ad6678f9fc08b26bdcbe26e8394551b9c5fb0457Matthew Fritze    private static Slice buildToggleSlice(Context context, SliceData sliceData,
234ad6678f9fc08b26bdcbe26e8394551b9c5fb0457Matthew Fritze            BasePreferenceController controller) {
23559e2d1fff968696aef3ea6e4944a8855e22de0feMatthew Fritze        final PendingIntent contentIntent = getContentPendingIntent(context, sliceData);
236f9f72e8c2c93d83aea2511174252cf3e3cd89819Matthew Fritze        final IconCompat icon = IconCompat.createWithResource(context, sliceData.getIconResource());
237ad6678f9fc08b26bdcbe26e8394551b9c5fb0457Matthew Fritze        final CharSequence subtitleText = getSubtitleText(context, controller, sliceData);
2387d565e97a3a56ac2f343d25e03b2a98833b7a997Matthew Fritze        @ColorInt final int color = Utils.getColorAccent(context);
239ad6678f9fc08b26bdcbe26e8394551b9c5fb0457Matthew Fritze        final TogglePreferenceController toggleController =
240ad6678f9fc08b26bdcbe26e8394551b9c5fb0457Matthew Fritze                (TogglePreferenceController) controller;
241fcdfc2d83fe3ff4fd2e75676023cbab895941151Matthew Fritze        final SliceAction sliceAction = getToggleAction(context, sliceData,
242ad6678f9fc08b26bdcbe26e8394551b9c5fb0457Matthew Fritze                toggleController.isChecked());
243ff865c898f82f8e5181d510ea0e9e1535b12a24bMatthew Fritze        final List<String> keywords = buildSliceKeywords(sliceData);
244ad6678f9fc08b26bdcbe26e8394551b9c5fb0457Matthew Fritze
2457d565e97a3a56ac2f343d25e03b2a98833b7a997Matthew Fritze        return new ListBuilder(context, sliceData.getUri(), ListBuilder.INFINITY)
2467d565e97a3a56ac2f343d25e03b2a98833b7a997Matthew Fritze                .setAccentColor(color)
247ad6678f9fc08b26bdcbe26e8394551b9c5fb0457Matthew Fritze                .addRow(rowBuilder -> rowBuilder
248ad6678f9fc08b26bdcbe26e8394551b9c5fb0457Matthew Fritze                        .setTitle(sliceData.getTitle())
249ad6678f9fc08b26bdcbe26e8394551b9c5fb0457Matthew Fritze                        .setSubtitle(subtitleText)
250f9f72e8c2c93d83aea2511174252cf3e3cd89819Matthew Fritze                        .setPrimaryAction(
251f9f72e8c2c93d83aea2511174252cf3e3cd89819Matthew Fritze                                new SliceAction(contentIntent, icon, sliceData.getTitle()))
252ad6678f9fc08b26bdcbe26e8394551b9c5fb0457Matthew Fritze                        .addEndItem(sliceAction))
25347a44e8fa4974193d692cc1d86201b18ba7adbfeMatthew Fritze                .setKeywords(keywords)
254ad6678f9fc08b26bdcbe26e8394551b9c5fb0457Matthew Fritze                .build();
255ad6678f9fc08b26bdcbe26e8394551b9c5fb0457Matthew Fritze    }
256ad6678f9fc08b26bdcbe26e8394551b9c5fb0457Matthew Fritze
257ad6678f9fc08b26bdcbe26e8394551b9c5fb0457Matthew Fritze    private static Slice buildIntentSlice(Context context, SliceData sliceData,
258ad6678f9fc08b26bdcbe26e8394551b9c5fb0457Matthew Fritze            BasePreferenceController controller) {
25959e2d1fff968696aef3ea6e4944a8855e22de0feMatthew Fritze        final PendingIntent contentIntent = getContentPendingIntent(context, sliceData);
260f9f72e8c2c93d83aea2511174252cf3e3cd89819Matthew Fritze        final IconCompat icon = IconCompat.createWithResource(context, sliceData.getIconResource());
261ad6678f9fc08b26bdcbe26e8394551b9c5fb0457Matthew Fritze        final CharSequence subtitleText = getSubtitleText(context, controller, sliceData);
2627d565e97a3a56ac2f343d25e03b2a98833b7a997Matthew Fritze        @ColorInt final int color = Utils.getColorAccent(context);
263ff865c898f82f8e5181d510ea0e9e1535b12a24bMatthew Fritze        final List<String> keywords = buildSliceKeywords(sliceData);
264ad6678f9fc08b26bdcbe26e8394551b9c5fb0457Matthew Fritze
2657d565e97a3a56ac2f343d25e03b2a98833b7a997Matthew Fritze        return new ListBuilder(context, sliceData.getUri(), ListBuilder.INFINITY)
2667d565e97a3a56ac2f343d25e03b2a98833b7a997Matthew Fritze                .setAccentColor(color)
267ad6678f9fc08b26bdcbe26e8394551b9c5fb0457Matthew Fritze                .addRow(rowBuilder -> rowBuilder
268ad6678f9fc08b26bdcbe26e8394551b9c5fb0457Matthew Fritze                        .setTitle(sliceData.getTitle())
269ad6678f9fc08b26bdcbe26e8394551b9c5fb0457Matthew Fritze                        .setSubtitle(subtitleText)
270f9f72e8c2c93d83aea2511174252cf3e3cd89819Matthew Fritze                        .setPrimaryAction(
271f9f72e8c2c93d83aea2511174252cf3e3cd89819Matthew Fritze                                new SliceAction(contentIntent, icon, sliceData.getTitle())))
27247a44e8fa4974193d692cc1d86201b18ba7adbfeMatthew Fritze                .setKeywords(keywords)
273ad6678f9fc08b26bdcbe26e8394551b9c5fb0457Matthew Fritze                .build();
274ad6678f9fc08b26bdcbe26e8394551b9c5fb0457Matthew Fritze    }
275ad6678f9fc08b26bdcbe26e8394551b9c5fb0457Matthew Fritze
276ad6678f9fc08b26bdcbe26e8394551b9c5fb0457Matthew Fritze    private static Slice buildSliderSlice(Context context, SliceData sliceData,
277ad6678f9fc08b26bdcbe26e8394551b9c5fb0457Matthew Fritze            BasePreferenceController controller) {
278f9f72e8c2c93d83aea2511174252cf3e3cd89819Matthew Fritze        final SliderPreferenceController sliderController = (SliderPreferenceController) controller;
279fcdfc2d83fe3ff4fd2e75676023cbab895941151Matthew Fritze        final PendingIntent actionIntent = getSliderAction(context, sliceData);
280f9f72e8c2c93d83aea2511174252cf3e3cd89819Matthew Fritze        final PendingIntent contentIntent = getContentPendingIntent(context, sliceData);
281f9f72e8c2c93d83aea2511174252cf3e3cd89819Matthew Fritze        final IconCompat icon = IconCompat.createWithResource(context, sliceData.getIconResource());
282250e26aff953490100297f5bb4afd76f2950c90eMatthew Fritze        final CharSequence subtitleText = getSubtitleText(context, controller, sliceData);
2837d565e97a3a56ac2f343d25e03b2a98833b7a997Matthew Fritze        @ColorInt final int color = Utils.getColorAccent(context);
284f9f72e8c2c93d83aea2511174252cf3e3cd89819Matthew Fritze        final SliceAction primaryAction = new SliceAction(contentIntent, icon,
285f9f72e8c2c93d83aea2511174252cf3e3cd89819Matthew Fritze                sliceData.getTitle());
286ff865c898f82f8e5181d510ea0e9e1535b12a24bMatthew Fritze        final List<String> keywords = buildSliceKeywords(sliceData);
287f9f72e8c2c93d83aea2511174252cf3e3cd89819Matthew Fritze
2887d565e97a3a56ac2f343d25e03b2a98833b7a997Matthew Fritze        return new ListBuilder(context, sliceData.getUri(), ListBuilder.INFINITY)
2897d565e97a3a56ac2f343d25e03b2a98833b7a997Matthew Fritze                .setAccentColor(color)
29093307cdb69bb3dd249fb9f130482c39a8636e9e5Matthew Fritze                .addInputRange(builder -> builder
291ad6678f9fc08b26bdcbe26e8394551b9c5fb0457Matthew Fritze                        .setTitle(sliceData.getTitle())
292250e26aff953490100297f5bb4afd76f2950c90eMatthew Fritze                        .setSubtitle(subtitleText)
29393307cdb69bb3dd249fb9f130482c39a8636e9e5Matthew Fritze                        .setPrimaryAction(primaryAction)
294ad6678f9fc08b26bdcbe26e8394551b9c5fb0457Matthew Fritze                        .setMax(sliderController.getMaxSteps())
295ad6678f9fc08b26bdcbe26e8394551b9c5fb0457Matthew Fritze                        .setValue(sliderController.getSliderPosition())
296250e26aff953490100297f5bb4afd76f2950c90eMatthew Fritze                        .setInputAction(actionIntent))
29747a44e8fa4974193d692cc1d86201b18ba7adbfeMatthew Fritze                .setKeywords(keywords)
298ad6678f9fc08b26bdcbe26e8394551b9c5fb0457Matthew Fritze                .build();
299ad6678f9fc08b26bdcbe26e8394551b9c5fb0457Matthew Fritze    }
300ad6678f9fc08b26bdcbe26e8394551b9c5fb0457Matthew Fritze
3011e9d9c7054270f92b4b7db4d3f405cb9ed38c051Matthew Fritze    private static BasePreferenceController getPreferenceController(Context context,
3021e9d9c7054270f92b4b7db4d3f405cb9ed38c051Matthew Fritze            String controllerClassName, String controllerKey) {
30364aa50c006dd3d2be51241f837436ec3713753e0Matthew Fritze        try {
3041e9d9c7054270f92b4b7db4d3f405cb9ed38c051Matthew Fritze            return BasePreferenceController.createInstance(context, controllerClassName);
30564aa50c006dd3d2be51241f837436ec3713753e0Matthew Fritze        } catch (IllegalStateException e) {
30664aa50c006dd3d2be51241f837436ec3713753e0Matthew Fritze            // Do nothing
30764aa50c006dd3d2be51241f837436ec3713753e0Matthew Fritze        }
30864aa50c006dd3d2be51241f837436ec3713753e0Matthew Fritze
3091e9d9c7054270f92b4b7db4d3f405cb9ed38c051Matthew Fritze        return BasePreferenceController.createInstance(context, controllerClassName, controllerKey);
3108c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritze    }
3118c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritze
312fcdfc2d83fe3ff4fd2e75676023cbab895941151Matthew Fritze    private static SliceAction getToggleAction(Context context, SliceData sliceData,
313fcdfc2d83fe3ff4fd2e75676023cbab895941151Matthew Fritze            boolean isChecked) {
3148c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritze        PendingIntent actionIntent = getActionIntent(context,
315fcdfc2d83fe3ff4fd2e75676023cbab895941151Matthew Fritze                SettingsSliceProvider.ACTION_TOGGLE_CHANGED, sliceData);
316ad6678f9fc08b26bdcbe26e8394551b9c5fb0457Matthew Fritze        return new SliceAction(actionIntent, null, isChecked);
317ad6678f9fc08b26bdcbe26e8394551b9c5fb0457Matthew Fritze    }
318ad6678f9fc08b26bdcbe26e8394551b9c5fb0457Matthew Fritze
319fcdfc2d83fe3ff4fd2e75676023cbab895941151Matthew Fritze    private static PendingIntent getSliderAction(Context context, SliceData sliceData) {
320fcdfc2d83fe3ff4fd2e75676023cbab895941151Matthew Fritze        return getActionIntent(context, SettingsSliceProvider.ACTION_SLIDER_CHANGED, sliceData);
3218c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritze    }
3228c96843fe3eb0766cf255fb5d7783f682db177b8Matthew Fritze
323906572b127e57aac01bfe1a45ddcc7f053883f47Fan Zhang    private static boolean isValidSummary(Context context, CharSequence summary) {
324906572b127e57aac01bfe1a45ddcc7f053883f47Fan Zhang        if (summary == null || TextUtils.isEmpty(summary.toString().trim())) {
32582254b08fd4d74c6a707fe20cec8c68a3e54b329Matthew Fritze            return false;
32682254b08fd4d74c6a707fe20cec8c68a3e54b329Matthew Fritze        }
32782254b08fd4d74c6a707fe20cec8c68a3e54b329Matthew Fritze
328906572b127e57aac01bfe1a45ddcc7f053883f47Fan Zhang        final CharSequence placeHolder = context.getText(R.string.summary_placeholder);
329906572b127e57aac01bfe1a45ddcc7f053883f47Fan Zhang        final CharSequence doublePlaceHolder =
330906572b127e57aac01bfe1a45ddcc7f053883f47Fan Zhang                context.getText(R.string.summary_two_lines_placeholder);
33182254b08fd4d74c6a707fe20cec8c68a3e54b329Matthew Fritze
33282254b08fd4d74c6a707fe20cec8c68a3e54b329Matthew Fritze        return !(TextUtils.equals(summary, placeHolder)
33382254b08fd4d74c6a707fe20cec8c68a3e54b329Matthew Fritze                || TextUtils.equals(summary, doublePlaceHolder));
33482254b08fd4d74c6a707fe20cec8c68a3e54b329Matthew Fritze    }
335fcdfc2d83fe3ff4fd2e75676023cbab895941151Matthew Fritze
336ff865c898f82f8e5181d510ea0e9e1535b12a24bMatthew Fritze    private static List<String> buildSliceKeywords(SliceData data) {
337ff865c898f82f8e5181d510ea0e9e1535b12a24bMatthew Fritze        final List<String> keywords = new ArrayList<>();
338ff865c898f82f8e5181d510ea0e9e1535b12a24bMatthew Fritze
339ff865c898f82f8e5181d510ea0e9e1535b12a24bMatthew Fritze        keywords.add(data.getTitle());
340ff865c898f82f8e5181d510ea0e9e1535b12a24bMatthew Fritze
341ff865c898f82f8e5181d510ea0e9e1535b12a24bMatthew Fritze        if (!TextUtils.equals(data.getTitle(), data.getScreenTitle())) {
342ff865c898f82f8e5181d510ea0e9e1535b12a24bMatthew Fritze            keywords.add(data.getScreenTitle().toString());
343ff865c898f82f8e5181d510ea0e9e1535b12a24bMatthew Fritze        }
344ff865c898f82f8e5181d510ea0e9e1535b12a24bMatthew Fritze
345ff865c898f82f8e5181d510ea0e9e1535b12a24bMatthew Fritze        final String keywordString = data.getKeywords();
346ff865c898f82f8e5181d510ea0e9e1535b12a24bMatthew Fritze        if (keywordString != null) {
347ff865c898f82f8e5181d510ea0e9e1535b12a24bMatthew Fritze            final String[] keywordArray = keywordString.split(",");
34846aa5866108e9b50d133977f8877d2456960ee6aMatthew Fritze            final List<String> strippedKeywords = Arrays.stream(keywordArray)
34946aa5866108e9b50d133977f8877d2456960ee6aMatthew Fritze                    .map(s -> s = s.trim())
35046aa5866108e9b50d133977f8877d2456960ee6aMatthew Fritze                    .collect(Collectors.toList());
35146aa5866108e9b50d133977f8877d2456960ee6aMatthew Fritze            keywords.addAll(strippedKeywords);
35247a44e8fa4974193d692cc1d86201b18ba7adbfeMatthew Fritze        }
35347a44e8fa4974193d692cc1d86201b18ba7adbfeMatthew Fritze
354ff865c898f82f8e5181d510ea0e9e1535b12a24bMatthew Fritze        return keywords;
35547a44e8fa4974193d692cc1d86201b18ba7adbfeMatthew Fritze    }
35647a44e8fa4974193d692cc1d86201b18ba7adbfeMatthew Fritze
357d9613b2742bdb8441b8050edfdf0a9772f7d45c9Matthew Fritze    private static Slice buildUnavailableSlice(Context context, SliceData data) {
358fcdfc2d83fe3ff4fd2e75676023cbab895941151Matthew Fritze        final String title = data.getTitle();
359ff865c898f82f8e5181d510ea0e9e1535b12a24bMatthew Fritze        final List<String> keywords = buildSliceKeywords(data);
3607d565e97a3a56ac2f343d25e03b2a98833b7a997Matthew Fritze        @ColorInt final int color = Utils.getColorAccent(context);
361d9613b2742bdb8441b8050edfdf0a9772f7d45c9Matthew Fritze        final CharSequence summary = context.getText(R.string.disabled_dependent_setting_summary);
362f9f72e8c2c93d83aea2511174252cf3e3cd89819Matthew Fritze        final IconCompat icon = IconCompat.createWithResource(context, data.getIconResource());
363d9613b2742bdb8441b8050edfdf0a9772f7d45c9Matthew Fritze        final SliceAction primaryAction = new SliceAction(getContentPendingIntent(context, data),
364d9613b2742bdb8441b8050edfdf0a9772f7d45c9Matthew Fritze                icon, title);
365fcdfc2d83fe3ff4fd2e75676023cbab895941151Matthew Fritze
3667d565e97a3a56ac2f343d25e03b2a98833b7a997Matthew Fritze        return new ListBuilder(context, data.getUri(), ListBuilder.INFINITY)
3677d565e97a3a56ac2f343d25e03b2a98833b7a997Matthew Fritze                .setAccentColor(color)
368fcdfc2d83fe3ff4fd2e75676023cbab895941151Matthew Fritze                .addRow(builder -> builder
369fcdfc2d83fe3ff4fd2e75676023cbab895941151Matthew Fritze                        .setTitle(title)
370d9613b2742bdb8441b8050edfdf0a9772f7d45c9Matthew Fritze                        .setTitleItem(icon)
371fcdfc2d83fe3ff4fd2e75676023cbab895941151Matthew Fritze                        .setSubtitle(summary)
372fcdfc2d83fe3ff4fd2e75676023cbab895941151Matthew Fritze                        .setPrimaryAction(primaryAction))
37347a44e8fa4974193d692cc1d86201b18ba7adbfeMatthew Fritze                .setKeywords(keywords)
374fcdfc2d83fe3ff4fd2e75676023cbab895941151Matthew Fritze                .build();
375fcdfc2d83fe3ff4fd2e75676023cbab895941151Matthew Fritze    }
3765ef0a604a9affd721472804ccf81bf35b96a7802Jason Monk}
377