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