1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.car.developeroptions.development;
18 
19 import android.app.Activity;
20 import android.app.settings.SettingsEnums;
21 import android.bluetooth.BluetoothA2dp;
22 import android.bluetooth.BluetoothAdapter;
23 import android.bluetooth.BluetoothCodecStatus;
24 import android.bluetooth.BluetoothProfile;
25 import android.content.BroadcastReceiver;
26 import android.content.Context;
27 import android.content.Intent;
28 import android.content.IntentFilter;
29 import android.os.Bundle;
30 import android.os.UserManager;
31 import android.provider.SearchIndexableResource;
32 import android.util.Log;
33 import android.view.LayoutInflater;
34 import android.view.View;
35 import android.view.ViewGroup;
36 import android.widget.Switch;
37 
38 import androidx.annotation.VisibleForTesting;
39 import androidx.localbroadcastmanager.content.LocalBroadcastManager;
40 
41 import com.android.car.developeroptions.R;
42 import com.android.car.developeroptions.SettingsActivity;
43 import com.android.car.developeroptions.Utils;
44 import com.android.car.developeroptions.dashboard.RestrictedDashboardFragment;
45 import com.android.car.developeroptions.development.autofill.AutofillLoggingLevelPreferenceController;
46 import com.android.car.developeroptions.development.autofill.AutofillResetOptionsPreferenceController;
47 import com.android.car.developeroptions.search.BaseSearchIndexProvider;
48 import com.android.car.developeroptions.search.Indexable;
49 import com.android.car.developeroptions.widget.SwitchBar;
50 import com.android.settingslib.core.AbstractPreferenceController;
51 import com.android.settingslib.core.lifecycle.Lifecycle;
52 import com.android.settingslib.development.DeveloperOptionsPreferenceController;
53 import com.android.settingslib.development.DevelopmentSettingsEnabler;
54 import com.android.settingslib.development.SystemPropPoker;
55 import com.android.settingslib.search.SearchIndexable;
56 
57 import java.util.ArrayList;
58 import java.util.Arrays;
59 import java.util.List;
60 
61 @SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
62 public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFragment
63         implements SwitchBar.OnSwitchChangeListener, OemUnlockDialogHost, AdbDialogHost,
64         AdbClearKeysDialogHost, LogPersistDialogHost,
65         BluetoothA2dpHwOffloadRebootDialog.OnA2dpHwDialogConfirmedListener {
66 
67     private static final String TAG = "DevSettingsDashboard";
68 
69     private final BluetoothA2dpConfigStore mBluetoothA2dpConfigStore =
70             new BluetoothA2dpConfigStore();
71 
72     private boolean mIsAvailable = true;
73     private SwitchBar mSwitchBar;
74     private DevelopmentSwitchBarController mSwitchBarController;
75     private List<AbstractPreferenceController> mPreferenceControllers = new ArrayList<>();
76     private BluetoothA2dp mBluetoothA2dp;
77 
78     private final BroadcastReceiver mEnableAdbReceiver = new BroadcastReceiver() {
79         @Override
80         public void onReceive(Context context, Intent intent) {
81             for (AbstractPreferenceController controller : mPreferenceControllers) {
82                 if (controller instanceof AdbOnChangeListener) {
83                     ((AdbOnChangeListener) controller).onAdbSettingChanged();
84                 }
85             }
86         }
87     };
88 
89     private final BroadcastReceiver mBluetoothA2dpReceiver = new BroadcastReceiver() {
90         @Override
91         public void onReceive(Context context, Intent intent) {
92             Log.d(TAG, "mBluetoothA2dpReceiver.onReceive intent=" + intent);
93             String action = intent.getAction();
94 
95             if (BluetoothA2dp.ACTION_CODEC_CONFIG_CHANGED.equals(action)) {
96                 BluetoothCodecStatus codecStatus = intent.getParcelableExtra(
97                         BluetoothCodecStatus.EXTRA_CODEC_STATUS);
98                 Log.d(TAG, "Received BluetoothCodecStatus=" + codecStatus);
99                 for (AbstractPreferenceController controller : mPreferenceControllers) {
100                     if (controller instanceof BluetoothServiceConnectionListener) {
101                         ((BluetoothServiceConnectionListener) controller).onBluetoothCodecUpdated();
102                     }
103                 }
104             }
105         }
106     };
107 
108 
109     private final BluetoothProfile.ServiceListener mBluetoothA2dpServiceListener =
110             new BluetoothProfile.ServiceListener() {
111                 @Override
112                 public void onServiceConnected(int profile,
113                         BluetoothProfile proxy) {
114                     synchronized (mBluetoothA2dpConfigStore) {
115                         mBluetoothA2dp = (BluetoothA2dp) proxy;
116                     }
117                     for (AbstractPreferenceController controller : mPreferenceControllers) {
118                         if (controller instanceof BluetoothServiceConnectionListener) {
119                             ((BluetoothServiceConnectionListener) controller)
120                                     .onBluetoothServiceConnected(mBluetoothA2dp);
121                         }
122                     }
123                 }
124 
125                 @Override
126                 public void onServiceDisconnected(int profile) {
127                     synchronized (mBluetoothA2dpConfigStore) {
128                         mBluetoothA2dp = null;
129                     }
130                     for (AbstractPreferenceController controller : mPreferenceControllers) {
131                         if (controller instanceof BluetoothServiceConnectionListener) {
132                             ((BluetoothServiceConnectionListener) controller)
133                                     .onBluetoothServiceDisconnected();
134                         }
135                     }
136                 }
137             };
138 
DevelopmentSettingsDashboardFragment()139     public DevelopmentSettingsDashboardFragment() {
140         super(UserManager.DISALLOW_DEBUGGING_FEATURES);
141     }
142 
143     @Override
onCreate(Bundle icicle)144     public void onCreate(Bundle icicle) {
145         super.onCreate(icicle);
146         if (Utils.isMonkeyRunning()) {
147             getActivity().finish();
148             return;
149         }
150     }
151 
152     @Override
onActivityCreated(Bundle icicle)153     public void onActivityCreated(Bundle icicle) {
154         super.onActivityCreated(icicle);
155         // Apply page-level restrictions
156         setIfOnlyAvailableForAdmins(true);
157         if (isUiRestricted() || !Utils.isDeviceProvisioned(getActivity())) {
158             // Block access to developer options if the user is not the owner, if user policy
159             // restricts it, or if the device has not been provisioned
160             mIsAvailable = false;
161             // Show error message
162             if (!isUiRestrictedByOnlyAdmin()) {
163                 getEmptyTextView().setText(R.string.development_settings_not_available);
164             }
165             getPreferenceScreen().removeAll();
166             return;
167         }
168         // Set up global switch
169         mSwitchBar = ((SettingsActivity) getActivity()).getSwitchBar();
170         mSwitchBarController = new DevelopmentSwitchBarController(
171                 this /* DevelopmentSettings */, mSwitchBar, mIsAvailable,
172                 getSettingsLifecycle());
173         mSwitchBar.show();
174 
175         // Restore UI state based on whether developer options is enabled
176         if (DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(getContext())) {
177             enableDeveloperOptions();
178         } else {
179             disableDeveloperOptions();
180         }
181     }
182 
183     @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)184     public View onCreateView(LayoutInflater inflater, ViewGroup container,
185             Bundle savedInstanceState) {
186         registerReceivers();
187 
188         final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
189         if (adapter != null) {
190             adapter.getProfileProxy(getActivity(), mBluetoothA2dpServiceListener,
191                     BluetoothProfile.A2DP);
192         }
193         return super.onCreateView(inflater, container, savedInstanceState);
194     }
195 
196     @Override
onDestroyView()197     public void onDestroyView() {
198         super.onDestroyView();
199         unregisterReceivers();
200 
201         final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
202         if (adapter != null) {
203             adapter.closeProfileProxy(BluetoothProfile.A2DP, mBluetoothA2dp);
204             mBluetoothA2dp = null;
205         }
206     }
207 
208     @Override
getMetricsCategory()209     public int getMetricsCategory() {
210         return SettingsEnums.DEVELOPMENT;
211     }
212 
213     @Override
onSwitchChanged(Switch switchView, boolean isChecked)214     public void onSwitchChanged(Switch switchView, boolean isChecked) {
215         if (switchView != mSwitchBar.getSwitch()) {
216             return;
217         }
218         final boolean developmentEnabledState =
219                 DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(getContext());
220         if (isChecked != developmentEnabledState) {
221             if (isChecked) {
222                 EnableDevelopmentSettingWarningDialog.show(this /* host */);
223             } else {
224                 final BluetoothA2dpHwOffloadPreferenceController controller =
225                         getDevelopmentOptionsController(
226                                 BluetoothA2dpHwOffloadPreferenceController.class);
227                 // If A2DP hardware offload isn't default value, we must reboot after disable
228                 // developer options. Show a dialog for the user to confirm.
229                 if (controller == null || controller.isDefaultValue()) {
230                     disableDeveloperOptions();
231                 } else {
232                     DisableDevSettingsDialogFragment.show(this /* host */);
233                 }
234             }
235         }
236     }
237 
238     @Override
onOemUnlockDialogConfirmed()239     public void onOemUnlockDialogConfirmed() {
240         final OemUnlockPreferenceController controller = getDevelopmentOptionsController(
241                 OemUnlockPreferenceController.class);
242         controller.onOemUnlockConfirmed();
243     }
244 
245     @Override
onOemUnlockDialogDismissed()246     public void onOemUnlockDialogDismissed() {
247         final OemUnlockPreferenceController controller = getDevelopmentOptionsController(
248                 OemUnlockPreferenceController.class);
249         controller.onOemUnlockDismissed();
250     }
251 
252     @Override
onEnableAdbDialogConfirmed()253     public void onEnableAdbDialogConfirmed() {
254         final AdbPreferenceController controller = getDevelopmentOptionsController(
255                 AdbPreferenceController.class);
256         controller.onAdbDialogConfirmed();
257 
258     }
259 
260     @Override
onEnableAdbDialogDismissed()261     public void onEnableAdbDialogDismissed() {
262         final AdbPreferenceController controller = getDevelopmentOptionsController(
263                 AdbPreferenceController.class);
264         controller.onAdbDialogDismissed();
265     }
266 
267     @Override
onAdbClearKeysDialogConfirmed()268     public void onAdbClearKeysDialogConfirmed() {
269         final ClearAdbKeysPreferenceController controller = getDevelopmentOptionsController(
270                 ClearAdbKeysPreferenceController.class);
271         controller.onClearAdbKeysConfirmed();
272     }
273 
274     @Override
onDisableLogPersistDialogConfirmed()275     public void onDisableLogPersistDialogConfirmed() {
276         final LogPersistPreferenceController controller = getDevelopmentOptionsController(
277                 LogPersistPreferenceController.class);
278         controller.onDisableLogPersistDialogConfirmed();
279     }
280 
281     @Override
onDisableLogPersistDialogRejected()282     public void onDisableLogPersistDialogRejected() {
283         final LogPersistPreferenceController controller = getDevelopmentOptionsController(
284                 LogPersistPreferenceController.class);
285         controller.onDisableLogPersistDialogRejected();
286     }
287 
288     @Override
onA2dpHwDialogConfirmed()289     public void onA2dpHwDialogConfirmed() {
290         final BluetoothA2dpHwOffloadPreferenceController controller =
291                 getDevelopmentOptionsController(BluetoothA2dpHwOffloadPreferenceController.class);
292         controller.onA2dpHwDialogConfirmed();
293     }
294 
295     @Override
onActivityResult(int requestCode, int resultCode, Intent data)296     public void onActivityResult(int requestCode, int resultCode, Intent data) {
297         boolean handledResult = false;
298         for (AbstractPreferenceController controller : mPreferenceControllers) {
299             if (controller instanceof OnActivityResultListener) {
300                 // We do not break early because it is possible for multiple controllers to
301                 // handle the same result code.
302                 handledResult |=
303                         ((OnActivityResultListener) controller).onActivityResult(
304                                 requestCode, resultCode, data);
305             }
306         }
307         if (!handledResult) {
308             super.onActivityResult(requestCode, resultCode, data);
309         }
310     }
311 
312     @Override
getLogTag()313     protected String getLogTag() {
314         return TAG;
315     }
316 
317     @Override
getHelpResource()318     public int getHelpResource() {
319         return 0;
320     }
321 
322     @Override
getPreferenceScreenResId()323     protected int getPreferenceScreenResId() {
324         return Utils.isMonkeyRunning()? R.xml.placeholder_prefs : R.xml.development_settings;
325     }
326 
327     @Override
createPreferenceControllers(Context context)328     protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
329         if (Utils.isMonkeyRunning()) {
330             mPreferenceControllers = new ArrayList<>();
331             return null;
332         }
333         mPreferenceControllers = buildPreferenceControllers(context, getActivity(),
334                 getSettingsLifecycle(), this /* devOptionsDashboardFragment */,
335                 new BluetoothA2dpConfigStore());
336         return mPreferenceControllers;
337     }
338 
registerReceivers()339     private void registerReceivers() {
340         LocalBroadcastManager.getInstance(getContext())
341                 .registerReceiver(mEnableAdbReceiver, new IntentFilter(
342                         AdbPreferenceController.ACTION_ENABLE_ADB_STATE_CHANGED));
343 
344         final IntentFilter filter = new IntentFilter();
345         filter.addAction(BluetoothA2dp.ACTION_CODEC_CONFIG_CHANGED);
346         getActivity().registerReceiver(mBluetoothA2dpReceiver, filter);
347     }
348 
unregisterReceivers()349     private void unregisterReceivers() {
350         LocalBroadcastManager.getInstance(getContext()).unregisterReceiver(mEnableAdbReceiver);
351         getActivity().unregisterReceiver(mBluetoothA2dpReceiver);
352     }
353 
enableDeveloperOptions()354     private void enableDeveloperOptions() {
355         if (Utils.isMonkeyRunning()) {
356             return;
357         }
358         DevelopmentSettingsEnabler.setDevelopmentSettingsEnabled(getContext(), true);
359         for (AbstractPreferenceController controller : mPreferenceControllers) {
360             if (controller instanceof DeveloperOptionsPreferenceController) {
361                 ((DeveloperOptionsPreferenceController) controller).onDeveloperOptionsEnabled();
362             }
363         }
364     }
365 
disableDeveloperOptions()366     private void disableDeveloperOptions() {
367         if (Utils.isMonkeyRunning()) {
368             return;
369         }
370         DevelopmentSettingsEnabler.setDevelopmentSettingsEnabled(getContext(), false);
371         final SystemPropPoker poker = SystemPropPoker.getInstance();
372         poker.blockPokes();
373         for (AbstractPreferenceController controller : mPreferenceControllers) {
374             if (controller instanceof DeveloperOptionsPreferenceController) {
375                 ((DeveloperOptionsPreferenceController) controller)
376                         .onDeveloperOptionsDisabled();
377             }
378         }
379         poker.unblockPokes();
380         poker.poke();
381     }
382 
onEnableDevelopmentOptionsConfirmed()383     void onEnableDevelopmentOptionsConfirmed() {
384         enableDeveloperOptions();
385     }
386 
onEnableDevelopmentOptionsRejected()387     void onEnableDevelopmentOptionsRejected() {
388         // Reset the toggle
389         mSwitchBar.setChecked(false);
390     }
391 
onDisableDevelopmentOptionsConfirmed()392     void onDisableDevelopmentOptionsConfirmed() {
393         disableDeveloperOptions();
394     }
395 
onDisableDevelopmentOptionsRejected()396     void onDisableDevelopmentOptionsRejected() {
397         // Reset the toggle
398         mSwitchBar.setChecked(true);
399     }
400 
buildPreferenceControllers(Context context, Activity activity, Lifecycle lifecycle, DevelopmentSettingsDashboardFragment fragment, BluetoothA2dpConfigStore bluetoothA2dpConfigStore)401     private static List<AbstractPreferenceController> buildPreferenceControllers(Context context,
402             Activity activity, Lifecycle lifecycle, DevelopmentSettingsDashboardFragment fragment,
403             BluetoothA2dpConfigStore bluetoothA2dpConfigStore) {
404         final List<AbstractPreferenceController> controllers = new ArrayList<>();
405         controllers.add(new MemoryUsagePreferenceController(context));
406         controllers.add(new SystemServerHeapDumpPreferenceController(context));
407         controllers.add(new LocalBackupPasswordPreferenceController(context));
408         controllers.add(new StayAwakePreferenceController(context, lifecycle));
409         controllers.add(new HdcpCheckingPreferenceController(context));
410         controllers.add(new BluetoothSnoopLogPreferenceController(context));
411         controllers.add(new OemUnlockPreferenceController(context, activity, fragment));
412         controllers.add(new FileEncryptionPreferenceController(context));
413         controllers.add(new PictureColorModePreferenceController(context, lifecycle));
414         controllers.add(new WebViewAppPreferenceController(context));
415         controllers.add(new CoolColorTemperaturePreferenceController(context));
416         controllers.add(new DisableAutomaticUpdatesPreferenceController(context));
417         controllers.add(new AdbPreferenceController(context, fragment));
418         controllers.add(new ClearAdbKeysPreferenceController(context, fragment));
419         controllers.add(new LocalTerminalPreferenceController(context));
420         controllers.add(new AutomaticSystemServerHeapDumpPreferenceController(context));
421         controllers.add(new MockLocationAppPreferenceController(context, fragment));
422         controllers.add(new DebugViewAttributesPreferenceController(context));
423         controllers.add(new SelectDebugAppPreferenceController(context, fragment));
424         controllers.add(new WaitForDebuggerPreferenceController(context));
425         controllers.add(new EnableGpuDebugLayersPreferenceController(context));
426         controllers.add(new VerifyAppsOverUsbPreferenceController(context));
427         controllers.add(new ArtVerifierPreferenceController(context));
428         controllers.add(new LogdSizePreferenceController(context));
429         controllers.add(new LogPersistPreferenceController(context, fragment, lifecycle));
430         controllers.add(new CameraLaserSensorPreferenceController(context));
431         controllers.add(new WifiDisplayCertificationPreferenceController(context));
432         controllers.add(new WifiVerboseLoggingPreferenceController(context));
433         controllers.add(new MobileDataAlwaysOnPreferenceController(context));
434         controllers.add(new TetheringHardwareAccelPreferenceController(context));
435         controllers.add(new BluetoothDeviceNoNamePreferenceController(context));
436         controllers.add(new BluetoothAbsoluteVolumePreferenceController(context));
437         controllers.add(new BluetoothAvrcpVersionPreferenceController(context));
438         controllers.add(new BluetoothA2dpHwOffloadPreferenceController(context, fragment));
439         controllers.add(new BluetoothAudioCodecPreferenceController(context, lifecycle,
440                 bluetoothA2dpConfigStore));
441         controllers.add(new BluetoothAudioSampleRatePreferenceController(context, lifecycle,
442                 bluetoothA2dpConfigStore));
443         controllers.add(new BluetoothAudioBitsPerSamplePreferenceController(context, lifecycle,
444                 bluetoothA2dpConfigStore));
445         controllers.add(new BluetoothAudioChannelModePreferenceController(context, lifecycle,
446                 bluetoothA2dpConfigStore));
447         controllers.add(new BluetoothAudioQualityPreferenceController(context, lifecycle,
448                 bluetoothA2dpConfigStore));
449         controllers.add(new BluetoothMaxConnectedAudioDevicesPreferenceController(context));
450         controllers.add(new ShowTapsPreferenceController(context));
451         controllers.add(new PointerLocationPreferenceController(context));
452         controllers.add(new ShowSurfaceUpdatesPreferenceController(context));
453         controllers.add(new ShowLayoutBoundsPreferenceController(context));
454         controllers.add(new RtlLayoutPreferenceController(context));
455         controllers.add(new WindowAnimationScalePreferenceController(context));
456         controllers.add(new EmulateDisplayCutoutPreferenceController(context));
457         controllers.add(new TransitionAnimationScalePreferenceController(context));
458         controllers.add(new AnimatorDurationScalePreferenceController(context));
459         controllers.add(new SecondaryDisplayPreferenceController(context));
460         controllers.add(new GpuViewUpdatesPreferenceController(context));
461         controllers.add(new HardwareLayersUpdatesPreferenceController(context));
462         controllers.add(new DebugGpuOverdrawPreferenceController(context));
463         controllers.add(new DebugNonRectClipOperationsPreferenceController(context));
464         controllers.add(new ForceDarkPreferenceController(context));
465         controllers.add(new ForceMSAAPreferenceController(context));
466         controllers.add(new HardwareOverlaysPreferenceController(context));
467         controllers.add(new SimulateColorSpacePreferenceController(context));
468         controllers.add(new UsbAudioRoutingPreferenceController(context));
469         controllers.add(new StrictModePreferenceController(context));
470         controllers.add(new ProfileGpuRenderingPreferenceController(context));
471         controllers.add(new KeepActivitiesPreferenceController(context));
472         controllers.add(new BackgroundProcessLimitPreferenceController(context));
473         controllers.add(new ShowFirstCrashDialogPreferenceController(context));
474         controllers.add(new AppsNotRespondingPreferenceController(context));
475         controllers.add(new NotificationChannelWarningsPreferenceController(context));
476         controllers.add(new AllowAppsOnExternalPreferenceController(context));
477         controllers.add(new ResizableActivityPreferenceController(context));
478         controllers.add(new FreeformWindowsPreferenceController(context));
479         controllers.add(new DesktopModePreferenceController(context));
480         controllers.add(new ShortcutManagerThrottlingPreferenceController(context));
481         controllers.add(new EnableGnssRawMeasFullTrackingPreferenceController(context));
482         controllers.add(new EnableUserSwitchMessageController(context));
483         controllers.add(new DefaultLaunchPreferenceController(context, "running_apps"));
484         controllers.add(new DefaultLaunchPreferenceController(context, "demo_mode"));
485         controllers.add(new DefaultLaunchPreferenceController(context, "quick_settings_tiles"));
486         controllers.add(new DefaultLaunchPreferenceController(context, "feature_flags_dashboard"));
487         controllers.add(
488             new DefaultLaunchPreferenceController(context, "default_usb_configuration"));
489         controllers.add(new DefaultLaunchPreferenceController(context, "density"));
490         controllers.add(new DefaultLaunchPreferenceController(context, "background_check"));
491         controllers.add(new DefaultLaunchPreferenceController(context, "inactive_apps"));
492         controllers.add(new AutofillLoggingLevelPreferenceController(context, lifecycle));
493         controllers.add(new AutofillResetOptionsPreferenceController(context));
494         controllers.add(new OverlayCategoryPreferenceController(context,
495                 "android.theme.customization.accent_color"));
496         controllers.add(new OverlayCategoryPreferenceController(context,
497                 "android.theme.customization.font"));
498         controllers.add(new OverlayCategoryPreferenceController(context,
499                 "android.theme.customization.adaptive_icon_shape"));
500         controllers.add(new TrustAgentsExtendUnlockPreferenceController(context));
501         controllers.add(new TrustLostLocksScreenPreferenceController(context));
502         return controllers;
503     }
504 
505     @VisibleForTesting
getDevelopmentOptionsController(Class<T> clazz)506     <T extends AbstractPreferenceController> T getDevelopmentOptionsController(Class<T> clazz) {
507         return use(clazz);
508     }
509 
510     /**
511      * For Search.
512      */
513     public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
514             new BaseSearchIndexProvider() {
515 
516                 @Override
517                 protected boolean isPageSearchEnabled(Context context) {
518                     return DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(context);
519                 }
520 
521                 @Override
522                 public List<SearchIndexableResource> getXmlResourcesToIndex(
523                         Context context, boolean enabled) {
524 
525                     final SearchIndexableResource sir = new SearchIndexableResource(context);
526                     sir.xmlResId = R.xml.development_settings;
527                     return Arrays.asList(sir);
528                 }
529 
530                 @Override
531                 public List<AbstractPreferenceController> createPreferenceControllers(Context
532                         context) {
533                     return buildPreferenceControllers(context, null /* activity */,
534                             null /* lifecycle */, null /* devOptionsDashboardFragment */,
535                             null /* bluetoothA2dpConfigStore */);
536                 }
537             };
538 }
539