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