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 static android.app.Activity.RESULT_OK; 20 import static android.provider.Settings.Global.DEVELOPMENT_SETTINGS_ENABLED; 21 import static android.service.quicksettings.TileService.ACTION_QS_TILE_PREFERENCES; 22 import static android.view.flags.Flags.sensitiveContentAppProtectionApi; 23 24 import android.app.Activity; 25 import android.app.settings.SettingsEnums; 26 import android.bluetooth.BluetoothA2dp; 27 import android.bluetooth.BluetoothAdapter; 28 import android.bluetooth.BluetoothCodecStatus; 29 import android.bluetooth.BluetoothProfile; 30 import android.content.BroadcastReceiver; 31 import android.content.ComponentName; 32 import android.content.ContentResolver; 33 import android.content.Context; 34 import android.content.Intent; 35 import android.content.IntentFilter; 36 import android.database.ContentObserver; 37 import android.net.Uri; 38 import android.os.Bundle; 39 import android.os.Handler; 40 import android.os.Looper; 41 import android.os.SystemProperties; 42 import android.os.UserManager; 43 import android.provider.Settings; 44 import android.text.TextUtils; 45 import android.util.Log; 46 import android.view.LayoutInflater; 47 import android.view.View; 48 import android.view.ViewGroup; 49 import android.widget.CompoundButton; 50 import android.widget.CompoundButton.OnCheckedChangeListener; 51 import android.widget.Toast; 52 53 import androidx.annotation.Nullable; 54 import androidx.annotation.VisibleForTesting; 55 import androidx.localbroadcastmanager.content.LocalBroadcastManager; 56 57 import com.android.settings.R; 58 import com.android.settings.SettingsActivity; 59 import com.android.settings.Utils; 60 import com.android.settings.biometrics.IdentityCheckBiometricErrorDialog; 61 import com.android.settings.core.SubSettingLauncher; 62 import com.android.settings.dashboard.RestrictedDashboardFragment; 63 import com.android.settings.development.autofill.AutofillCategoryController; 64 import com.android.settings.development.autofill.AutofillLoggingLevelPreferenceController; 65 import com.android.settings.development.autofill.AutofillResetOptionsPreferenceController; 66 import com.android.settings.development.bluetooth.AbstractBluetoothDialogPreferenceController; 67 import com.android.settings.development.bluetooth.AbstractBluetoothPreferenceController; 68 import com.android.settings.development.bluetooth.BluetoothBitPerSampleDialogPreferenceController; 69 import com.android.settings.development.bluetooth.BluetoothChannelModeDialogPreferenceController; 70 import com.android.settings.development.bluetooth.BluetoothCodecListPreferenceController; 71 import com.android.settings.development.bluetooth.BluetoothHDAudioPreferenceController; 72 import com.android.settings.development.bluetooth.BluetoothQualityDialogPreferenceController; 73 import com.android.settings.development.bluetooth.BluetoothSampleRateDialogPreferenceController; 74 import com.android.settings.development.bluetooth.BluetoothStackLogPreferenceController; 75 import com.android.settings.development.desktopexperience.DesktopExperiencePreferenceController; 76 import com.android.settings.development.desktopexperience.DesktopModePreferenceController; 77 import com.android.settings.development.desktopexperience.DesktopModeSecondaryDisplayPreferenceController; 78 import com.android.settings.development.desktopexperience.FreeformWindowsPreferenceController; 79 import com.android.settings.development.graphicsdriver.GraphicsDriverEnableAngleAsSystemDriverController; 80 import com.android.settings.development.linuxterminal.LinuxTerminalPreferenceController; 81 import com.android.settings.development.qstile.DevelopmentTiles; 82 import com.android.settings.development.storage.SharedDataPreferenceController; 83 import com.android.settings.development.window.NonResizableMultiWindowPreferenceController; 84 import com.android.settings.development.window.ResizableActivityPreferenceController; 85 import com.android.settings.overlay.FeatureFactory; 86 import com.android.settings.password.ConfirmDeviceCredentialActivity; 87 import com.android.settings.search.BaseSearchIndexProvider; 88 import com.android.settings.search.actionbar.SearchMenuController; 89 import com.android.settings.widget.SettingsMainSwitchBar; 90 import com.android.settingslib.core.AbstractPreferenceController; 91 import com.android.settingslib.core.lifecycle.Lifecycle; 92 import com.android.settingslib.development.DeveloperOptionsPreferenceController; 93 import com.android.settingslib.development.DevelopmentSettingsEnabler; 94 import com.android.settingslib.development.SystemPropPoker; 95 import com.android.settingslib.search.SearchIndexable; 96 97 import com.google.android.setupcompat.util.WizardManagerHelper; 98 99 import java.util.ArrayList; 100 import java.util.List; 101 102 @SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC) 103 public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFragment 104 implements OnCheckedChangeListener, OemUnlockDialogHost, AdbDialogHost, 105 AdbClearKeysDialogHost, LogPersistDialogHost, 106 BluetoothRebootDialog.OnRebootDialogListener, 107 AbstractBluetoothPreferenceController.Callback, 108 NfcRebootDialog.OnNfcRebootDialogConfirmedListener, 109 BluetoothSnoopLogHost, 110 BluetoothLeAudioModePreferenceController.OnModeChangeListener { 111 112 private static final String TAG = "DevSettingsDashboard"; 113 @VisibleForTesting static final int REQUEST_BIOMETRIC_PROMPT = 100; 114 115 private final BluetoothA2dpConfigStore mBluetoothA2dpConfigStore = 116 new BluetoothA2dpConfigStore(); 117 118 private boolean mIsAvailable = true; 119 private boolean mIsBiometricsAuthenticated; 120 private SettingsMainSwitchBar mSwitchBar; 121 private DevelopmentSwitchBarController mSwitchBarController; 122 private List<AbstractPreferenceController> mPreferenceControllers = new ArrayList<>(); 123 private BluetoothA2dp mBluetoothA2dp; 124 125 private final BroadcastReceiver mEnableAdbReceiver = new BroadcastReceiver() { 126 @Override 127 public void onReceive(Context context, Intent intent) { 128 for (AbstractPreferenceController controller : mPreferenceControllers) { 129 if (controller instanceof AdbOnChangeListener) { 130 ((AdbOnChangeListener) controller).onAdbSettingChanged(); 131 } 132 } 133 } 134 }; 135 136 private final BroadcastReceiver mBluetoothA2dpReceiver = new BroadcastReceiver() { 137 @Override 138 public void onReceive(Context context, Intent intent) { 139 Log.d(TAG, "mBluetoothA2dpReceiver.onReceive intent=" + intent); 140 String action = intent.getAction(); 141 142 if (BluetoothA2dp.ACTION_CODEC_CONFIG_CHANGED.equals(action)) { 143 BluetoothCodecStatus codecStatus = intent.getParcelableExtra( 144 BluetoothCodecStatus.EXTRA_CODEC_STATUS); 145 Log.d(TAG, "Received BluetoothCodecStatus=" + codecStatus); 146 for (AbstractPreferenceController controller : mPreferenceControllers) { 147 if (controller instanceof BluetoothServiceConnectionListener) { 148 ((BluetoothServiceConnectionListener) controller).onBluetoothCodecUpdated(); 149 } 150 } 151 } 152 } 153 }; 154 155 156 private final BluetoothProfile.ServiceListener mBluetoothA2dpServiceListener = 157 new BluetoothProfile.ServiceListener() { 158 @Override 159 public void onServiceConnected(int profile, 160 BluetoothProfile proxy) { 161 synchronized (mBluetoothA2dpConfigStore) { 162 mBluetoothA2dp = (BluetoothA2dp) proxy; 163 } 164 for (AbstractPreferenceController controller : mPreferenceControllers) { 165 if (controller instanceof BluetoothServiceConnectionListener) { 166 ((BluetoothServiceConnectionListener) controller) 167 .onBluetoothServiceConnected(mBluetoothA2dp); 168 } 169 } 170 } 171 172 @Override 173 public void onServiceDisconnected(int profile) { 174 synchronized (mBluetoothA2dpConfigStore) { 175 mBluetoothA2dp = null; 176 } 177 for (AbstractPreferenceController controller : mPreferenceControllers) { 178 if (controller instanceof BluetoothServiceConnectionListener) { 179 ((BluetoothServiceConnectionListener) controller) 180 .onBluetoothServiceDisconnected(); 181 } 182 } 183 } 184 }; 185 186 private final Runnable mSystemPropertiesChanged = new Runnable() { 187 @Override 188 public void run() { 189 synchronized (this) { 190 Activity activity = getActivity(); 191 if (activity != null) { 192 activity.runOnUiThread(() -> { 193 updatePreferenceStates(); 194 }); 195 } 196 } 197 } 198 }; 199 200 private final Uri mDevelopEnabled = Settings.Global.getUriFor(DEVELOPMENT_SETTINGS_ENABLED); 201 private final ContentObserver mDeveloperSettingsObserver = new ContentObserver(new Handler( 202 Looper.getMainLooper())) { 203 204 @Override 205 public void onChange(boolean selfChange, Uri uri) { 206 super.onChange(selfChange, uri); 207 Activity activity = getActivity(); 208 if (activity == null) { 209 return; 210 } 211 final boolean developmentEnabledState = 212 DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(activity); 213 final boolean switchState = mSwitchBar.isChecked(); 214 215 // when developer options is enabled, but it is disabled by other privilege apps like: 216 // adb command, we should disable all items and finish the activity. 217 if (developmentEnabledState != switchState) { 218 if (developmentEnabledState) { 219 return; 220 } 221 disableDeveloperOptions(); 222 activity.runOnUiThread(() -> finishFragment()); 223 } 224 } 225 }; 226 DevelopmentSettingsDashboardFragment()227 public DevelopmentSettingsDashboardFragment() { 228 super(UserManager.DISALLOW_DEBUGGING_FEATURES); 229 } 230 231 @Override onStart()232 public void onStart() { 233 super.onStart(); 234 final ContentResolver cr = getContext().getContentResolver(); 235 mIsBiometricsAuthenticated = false; 236 cr.registerContentObserver(mDevelopEnabled, false, mDeveloperSettingsObserver); 237 238 // Restore UI state based on whether developer options is enabled 239 if (DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(getContext())) { 240 enableDeveloperOptions(); 241 handleQsTileLongPressActionIfAny(); 242 } else { 243 disableDeveloperOptions(); 244 } 245 } 246 247 @Override onStop()248 public void onStop() { 249 super.onStop(); 250 final ContentResolver cr = getContext().getContentResolver(); 251 cr.unregisterContentObserver(mDeveloperSettingsObserver); 252 } 253 254 @Override onCreate(Bundle icicle)255 public void onCreate(Bundle icicle) { 256 super.onCreate(icicle); 257 SearchMenuController.init(this); 258 if (Utils.isMonkeyRunning()) { 259 getActivity().finish(); 260 return; 261 } 262 Context context = requireContext(); 263 UserManager um = (UserManager) getSystemService(Context.USER_SERVICE); 264 265 if (!um.isAdminUser()) { 266 Toast.makeText(context, R.string.dev_settings_available_to_admin_only_warning, 267 Toast.LENGTH_SHORT) 268 .show(); 269 finish(); 270 } else if (!DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(context)) { 271 Toast.makeText(context, R.string.dev_settings_disabled_warning, Toast.LENGTH_SHORT) 272 .show(); 273 finish(); 274 } 275 } 276 277 @Override onActivityCreated(Bundle icicle)278 public void onActivityCreated(Bundle icicle) { 279 super.onActivityCreated(icicle); 280 // Apply page-level restrictions 281 setIfOnlyAvailableForAdmins(true); 282 if (isUiRestricted() || !WizardManagerHelper.isDeviceProvisioned(getActivity())) { 283 // Block access to developer options if the user is not the owner, if user policy 284 // restricts it, or if the device has not been provisioned 285 mIsAvailable = false; 286 // Show error message 287 if (!isUiRestrictedByOnlyAdmin()) { 288 getEmptyTextView().setText( 289 com.android.settingslib.R.string.development_settings_not_available); 290 } 291 getPreferenceScreen().removeAll(); 292 return; 293 } 294 // Set up primary switch 295 mSwitchBar = ((SettingsActivity) getActivity()).getSwitchBar(); 296 mSwitchBar.setTitle(getContext().getString(R.string.developer_options_main_switch_title)); 297 mSwitchBar.show(); 298 mSwitchBarController = new DevelopmentSwitchBarController( 299 this /* DevelopmentSettings */, mSwitchBar, mIsAvailable, 300 getSettingsLifecycle()); 301 } 302 303 @Override shouldSkipForInitialSUW()304 protected boolean shouldSkipForInitialSUW() { 305 return true; 306 } 307 308 /** 309 * Long-pressing a developer options quick settings tile will by default (see 310 * QS_TILE_PREFERENCES in the manifest) take you to the developer options page. 311 * Some tiles may want to go into their own page within the developer options. 312 */ handleQsTileLongPressActionIfAny()313 private void handleQsTileLongPressActionIfAny() { 314 Intent intent = getActivity().getIntent(); 315 if (intent == null || !TextUtils.equals(ACTION_QS_TILE_PREFERENCES, intent.getAction())) { 316 return; 317 } 318 319 Log.d(TAG, "Developer options started from qstile long-press"); 320 final ComponentName componentName = (ComponentName) intent.getParcelableExtra( 321 Intent.EXTRA_COMPONENT_NAME); 322 if (componentName == null) { 323 return; 324 } 325 326 if (DevelopmentTiles.WirelessDebugging.class.getName().equals( 327 componentName.getClassName()) && getDevelopmentOptionsController( 328 WirelessDebuggingPreferenceController.class).isAvailable()) { 329 Log.d(TAG, "Long press from wireless debugging qstile"); 330 new SubSettingLauncher(getContext()) 331 .setDestination(WirelessDebuggingFragment.class.getName()) 332 .setSourceMetricsCategory(SettingsEnums.SETTINGS_ADB_WIRELESS) 333 .launch(); 334 } 335 // Add other qstiles here 336 } 337 338 @Override onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)339 public View onCreateView(LayoutInflater inflater, ViewGroup container, 340 Bundle savedInstanceState) { 341 registerReceivers(); 342 SystemProperties.addChangeCallback(mSystemPropertiesChanged); 343 final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 344 if (adapter != null) { 345 adapter.getProfileProxy(getActivity(), mBluetoothA2dpServiceListener, 346 BluetoothProfile.A2DP); 347 } 348 View root = super.onCreateView(inflater, container, savedInstanceState); 349 // Mark the view sensitive to black out the screen during screen share. 350 if (sensitiveContentAppProtectionApi()) { 351 root.setContentSensitivity(View.CONTENT_SENSITIVITY_SENSITIVE); 352 } 353 return root; 354 } 355 356 @Override onDestroyView()357 public void onDestroyView() { 358 super.onDestroyView(); 359 unregisterReceivers(); 360 361 final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 362 if (adapter != null) { 363 adapter.closeProfileProxy(BluetoothProfile.A2DP, mBluetoothA2dp); 364 mBluetoothA2dp = null; 365 } 366 SystemProperties.removeChangeCallback(mSystemPropertiesChanged); 367 } 368 369 @Override getMetricsCategory()370 public int getMetricsCategory() { 371 return SettingsEnums.DEVELOPMENT; 372 } 373 374 @Override onCheckedChanged(CompoundButton buttonView, boolean isChecked)375 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 376 final boolean developmentEnabledState = 377 DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(getContext()); 378 if (isChecked != developmentEnabledState) { 379 if (isChecked) { 380 final int userId = getContext().getUserId(); 381 382 final Utils.BiometricStatus biometricAuthStatus = 383 Utils.requestBiometricAuthenticationForMandatoryBiometrics( 384 getContext(), 385 mIsBiometricsAuthenticated, 386 userId); 387 if (biometricAuthStatus == Utils.BiometricStatus.OK) { 388 mSwitchBar.setChecked(false); 389 Utils.launchBiometricPromptForMandatoryBiometrics(this, 390 REQUEST_BIOMETRIC_PROMPT, 391 userId, false /* hideBackground */); 392 } else if (biometricAuthStatus != Utils.BiometricStatus.NOT_ACTIVE) { 393 mSwitchBar.setChecked(false); 394 IdentityCheckBiometricErrorDialog.showBiometricErrorDialog(getActivity(), 395 biometricAuthStatus, false /* twoFactorAuthentication */); 396 } else { 397 //Reset biometrics once enable dialog is shown 398 mIsBiometricsAuthenticated = false; 399 EnableDevelopmentSettingWarningDialog.show(this /* host */); 400 } 401 } else { 402 final BluetoothA2dpHwOffloadPreferenceController a2dpController = 403 getDevelopmentOptionsController( 404 BluetoothA2dpHwOffloadPreferenceController.class); 405 final BluetoothLeAudioHwOffloadPreferenceController leAudioController = 406 getDevelopmentOptionsController( 407 BluetoothLeAudioHwOffloadPreferenceController.class); 408 final NfcSnoopLogPreferenceController nfcSnoopLogController = 409 getDevelopmentOptionsController( 410 NfcSnoopLogPreferenceController.class); 411 final NfcVerboseVendorLogPreferenceController nfcVerboseLogController = 412 getDevelopmentOptionsController( 413 NfcVerboseVendorLogPreferenceController.class); 414 final GraphicsDriverEnableAngleAsSystemDriverController enableAngleController = 415 getDevelopmentOptionsController( 416 GraphicsDriverEnableAngleAsSystemDriverController.class); 417 // If hardware offload isn't default value, we must reboot after disable 418 // developer options. Show a dialog for the user to confirm. 419 if ((a2dpController == null || a2dpController.isDefaultValue()) 420 && (leAudioController == null || leAudioController.isDefaultValue()) 421 && (nfcSnoopLogController == null || nfcSnoopLogController.isDefaultValue()) 422 && (nfcVerboseLogController == null 423 || nfcVerboseLogController.isDefaultValue()) 424 && (enableAngleController == null 425 || enableAngleController.isDefaultValue())) { 426 disableDeveloperOptions(); 427 } else { 428 // Disabling developer options in page-agnostic mode isn't supported as device 429 // isn't in production state 430 if (Enable16kUtils.isPageAgnosticModeOn(getContext())) { 431 Enable16kUtils.showPageAgnosticWarning(getContext()); 432 onDisableDevelopmentOptionsRejected(); 433 return; 434 } 435 DisableDevSettingsDialogFragment.show(this /* host */); 436 } 437 } 438 FeatureFactory.getFeatureFactory().getSearchFeatureProvider() 439 .sendPreIndexIntent(getContext()); 440 } 441 } 442 443 @Override onOemUnlockDialogConfirmed()444 public void onOemUnlockDialogConfirmed() { 445 final OemUnlockPreferenceController controller = getDevelopmentOptionsController( 446 OemUnlockPreferenceController.class); 447 controller.onOemUnlockConfirmed(); 448 } 449 450 @Override onOemUnlockDialogDismissed()451 public void onOemUnlockDialogDismissed() { 452 final OemUnlockPreferenceController controller = getDevelopmentOptionsController( 453 OemUnlockPreferenceController.class); 454 controller.onOemUnlockDismissed(); 455 } 456 457 @Override onEnableAdbDialogConfirmed()458 public void onEnableAdbDialogConfirmed() { 459 final AdbPreferenceController controller = getDevelopmentOptionsController( 460 AdbPreferenceController.class); 461 controller.onAdbDialogConfirmed(); 462 463 } 464 465 @Override onEnableAdbDialogDismissed()466 public void onEnableAdbDialogDismissed() { 467 final AdbPreferenceController controller = getDevelopmentOptionsController( 468 AdbPreferenceController.class); 469 controller.onAdbDialogDismissed(); 470 } 471 472 @Override onAdbClearKeysDialogConfirmed()473 public void onAdbClearKeysDialogConfirmed() { 474 final ClearAdbKeysPreferenceController controller = getDevelopmentOptionsController( 475 ClearAdbKeysPreferenceController.class); 476 controller.onClearAdbKeysConfirmed(); 477 } 478 479 @Override onDisableLogPersistDialogConfirmed()480 public void onDisableLogPersistDialogConfirmed() { 481 final LogPersistPreferenceController controller = getDevelopmentOptionsController( 482 LogPersistPreferenceController.class); 483 controller.onDisableLogPersistDialogConfirmed(); 484 } 485 486 @Override onDisableLogPersistDialogRejected()487 public void onDisableLogPersistDialogRejected() { 488 final LogPersistPreferenceController controller = getDevelopmentOptionsController( 489 LogPersistPreferenceController.class); 490 controller.onDisableLogPersistDialogRejected(); 491 } 492 493 @Override onRebootDialogConfirmed()494 public void onRebootDialogConfirmed() { 495 final BluetoothA2dpHwOffloadPreferenceController a2dpController = 496 getDevelopmentOptionsController(BluetoothA2dpHwOffloadPreferenceController.class); 497 a2dpController.onRebootDialogConfirmed(); 498 499 final BluetoothLeAudioHwOffloadPreferenceController leAudioController = 500 getDevelopmentOptionsController( 501 BluetoothLeAudioHwOffloadPreferenceController.class); 502 leAudioController.onRebootDialogConfirmed(); 503 504 final BluetoothLeAudioPreferenceController leAudioFeatureController = 505 getDevelopmentOptionsController( 506 BluetoothLeAudioPreferenceController.class); 507 leAudioFeatureController.onRebootDialogConfirmed(); 508 509 final BluetoothLeAudioModePreferenceController leAudioModeController = 510 getDevelopmentOptionsController( 511 BluetoothLeAudioModePreferenceController.class); 512 leAudioModeController.onRebootDialogConfirmed(); 513 514 final BluetoothLeAudioUiPreferenceController leAudioUiController = 515 getDevelopmentOptionsController(BluetoothLeAudioUiPreferenceController.class); 516 leAudioUiController.onRebootDialogConfirmed(); 517 } 518 519 @Override onRebootDialogCanceled()520 public void onRebootDialogCanceled() { 521 final BluetoothA2dpHwOffloadPreferenceController a2dpController = 522 getDevelopmentOptionsController(BluetoothA2dpHwOffloadPreferenceController.class); 523 a2dpController.onRebootDialogCanceled(); 524 525 final BluetoothLeAudioHwOffloadPreferenceController leAudioController = 526 getDevelopmentOptionsController( 527 BluetoothLeAudioHwOffloadPreferenceController.class); 528 leAudioController.onRebootDialogCanceled(); 529 530 final BluetoothLeAudioPreferenceController leAudioFeatureController = 531 getDevelopmentOptionsController( 532 BluetoothLeAudioPreferenceController.class); 533 leAudioFeatureController.onRebootDialogCanceled(); 534 535 final BluetoothLeAudioModePreferenceController leAudioModeController = 536 getDevelopmentOptionsController( 537 BluetoothLeAudioModePreferenceController.class); 538 leAudioModeController.onRebootDialogCanceled(); 539 540 final BluetoothLeAudioUiPreferenceController leAudioUiController = 541 getDevelopmentOptionsController(BluetoothLeAudioUiPreferenceController.class); 542 leAudioUiController.onRebootDialogCanceled(); 543 } 544 545 @Override onNfcRebootDialogConfirmed()546 public void onNfcRebootDialogConfirmed() { 547 final NfcSnoopLogPreferenceController controller = 548 getDevelopmentOptionsController(NfcSnoopLogPreferenceController.class); 549 controller.onNfcRebootDialogConfirmed(); 550 551 final NfcVerboseVendorLogPreferenceController vendorLogController = 552 getDevelopmentOptionsController(NfcVerboseVendorLogPreferenceController.class); 553 vendorLogController.onNfcRebootDialogConfirmed(); 554 } 555 556 @Override onNfcRebootDialogCanceled()557 public void onNfcRebootDialogCanceled() { 558 final NfcSnoopLogPreferenceController controller = 559 getDevelopmentOptionsController(NfcSnoopLogPreferenceController.class); 560 controller.onNfcRebootDialogCanceled(); 561 562 final NfcVerboseVendorLogPreferenceController vendorLogController = 563 getDevelopmentOptionsController(NfcVerboseVendorLogPreferenceController.class); 564 vendorLogController.onNfcRebootDialogCanceled(); 565 } 566 567 @Override onSettingChanged()568 public void onSettingChanged() { 569 final BluetoothSnoopLogFilterProfileMapPreferenceController controllerMap = 570 getDevelopmentOptionsController( 571 BluetoothSnoopLogFilterProfileMapPreferenceController.class); 572 final BluetoothSnoopLogFilterProfilePbapPreferenceController controllerPbap = 573 getDevelopmentOptionsController( 574 BluetoothSnoopLogFilterProfilePbapPreferenceController.class); 575 controllerMap.onSettingChanged(); 576 controllerPbap.onSettingChanged(); 577 } 578 579 @Override onActivityResult(int requestCode, int resultCode, Intent data)580 public void onActivityResult(int requestCode, int resultCode, Intent data) { 581 boolean handledResult = false; 582 if (requestCode == REQUEST_BIOMETRIC_PROMPT) { 583 if (resultCode == RESULT_OK) { 584 mIsBiometricsAuthenticated = true; 585 mSwitchBar.setChecked(true); 586 } else if (resultCode 587 == ConfirmDeviceCredentialActivity.BIOMETRIC_LOCKOUT_ERROR_RESULT) { 588 IdentityCheckBiometricErrorDialog.showBiometricErrorDialog(getActivity(), 589 Utils.BiometricStatus.LOCKOUT, false /* twoFactorAuthentication */); 590 } 591 } 592 for (AbstractPreferenceController controller : mPreferenceControllers) { 593 if (controller instanceof OnActivityResultListener) { 594 // We do not break early because it is possible for multiple controllers to 595 // handle the same result code. 596 handledResult |= 597 ((OnActivityResultListener) controller).onActivityResult( 598 requestCode, resultCode, data); 599 } 600 } 601 if (!handledResult) { 602 super.onActivityResult(requestCode, resultCode, data); 603 } 604 } 605 606 @Override getLogTag()607 protected String getLogTag() { 608 return TAG; 609 } 610 611 @Override getHelpResource()612 public int getHelpResource() { 613 return 0; 614 } 615 616 @Override getPreferenceScreenResId()617 protected int getPreferenceScreenResId() { 618 return Utils.isMonkeyRunning() ? R.xml.placeholder_prefs : R.xml.development_settings; 619 } 620 621 @Override createPreferenceControllers(Context context)622 protected List<AbstractPreferenceController> createPreferenceControllers(Context context) { 623 if (Utils.isMonkeyRunning()) { 624 mPreferenceControllers = new ArrayList<>(); 625 return null; 626 } 627 mPreferenceControllers = buildPreferenceControllers(context, getActivity(), 628 getSettingsLifecycle(), this /* devOptionsDashboardFragment */, 629 new BluetoothA2dpConfigStore()); 630 return mPreferenceControllers; 631 } 632 registerReceivers()633 private void registerReceivers() { 634 LocalBroadcastManager.getInstance(getContext()) 635 .registerReceiver(mEnableAdbReceiver, new IntentFilter( 636 AdbPreferenceController.ACTION_ENABLE_ADB_STATE_CHANGED)); 637 638 final IntentFilter filter = new IntentFilter(); 639 filter.addAction(BluetoothA2dp.ACTION_CODEC_CONFIG_CHANGED); 640 getActivity().registerReceiver(mBluetoothA2dpReceiver, filter); 641 } 642 unregisterReceivers()643 private void unregisterReceivers() { 644 LocalBroadcastManager.getInstance(getContext()).unregisterReceiver(mEnableAdbReceiver); 645 getActivity().unregisterReceiver(mBluetoothA2dpReceiver); 646 } 647 enableDeveloperOptions()648 private void enableDeveloperOptions() { 649 if (Utils.isMonkeyRunning()) { 650 return; 651 } 652 DevelopmentSettingsEnabler.setDevelopmentSettingsEnabled(getContext(), true); 653 for (AbstractPreferenceController controller : mPreferenceControllers) { 654 if (controller instanceof DeveloperOptionsPreferenceController) { 655 ((DeveloperOptionsPreferenceController) controller).onDeveloperOptionsEnabled(); 656 } 657 } 658 } 659 disableDeveloperOptions()660 private void disableDeveloperOptions() { 661 if (Utils.isMonkeyRunning()) { 662 return; 663 } 664 665 // Disabling developer options in page-agnostic mode isn't supported as device isn't in 666 // production state 667 if (Enable16kUtils.isPageAgnosticModeOn(getContext())) { 668 Enable16kUtils.showPageAgnosticWarning(getContext()); 669 onDisableDevelopmentOptionsRejected(); 670 return; 671 } 672 673 DevelopmentSettingsEnabler.setDevelopmentSettingsEnabled(getContext(), false); 674 final SystemPropPoker poker = SystemPropPoker.getInstance(); 675 poker.blockPokes(); 676 for (AbstractPreferenceController controller : mPreferenceControllers) { 677 if (controller instanceof DeveloperOptionsPreferenceController) { 678 ((DeveloperOptionsPreferenceController) controller) 679 .onDeveloperOptionsDisabled(); 680 } 681 } 682 poker.unblockPokes(); 683 poker.poke(); 684 } 685 onEnableDevelopmentOptionsConfirmed()686 void onEnableDevelopmentOptionsConfirmed() { 687 enableDeveloperOptions(); 688 } 689 onEnableDevelopmentOptionsRejected()690 void onEnableDevelopmentOptionsRejected() { 691 // Reset the toggle 692 mSwitchBar.setChecked(false); 693 } 694 onDisableDevelopmentOptionsConfirmed()695 void onDisableDevelopmentOptionsConfirmed() { 696 disableDeveloperOptions(); 697 } 698 onDisableDevelopmentOptionsRejected()699 void onDisableDevelopmentOptionsRejected() { 700 // Reset the toggle 701 mSwitchBar.setChecked(true); 702 } 703 buildPreferenceControllers(Context context, @Nullable Activity activity, @Nullable Lifecycle lifecycle, @Nullable DevelopmentSettingsDashboardFragment fragment, @Nullable BluetoothA2dpConfigStore bluetoothA2dpConfigStore)704 private static List<AbstractPreferenceController> buildPreferenceControllers(Context context, 705 @Nullable Activity activity, @Nullable Lifecycle lifecycle, 706 @Nullable DevelopmentSettingsDashboardFragment fragment, 707 @Nullable BluetoothA2dpConfigStore bluetoothA2dpConfigStore) { 708 final List<AbstractPreferenceController> controllers = new ArrayList<>(); 709 controllers.add(new MemoryUsagePreferenceController(context)); 710 controllers.add(new BugReportPreferenceController(context)); 711 controllers.add(new BugReportHandlerPreferenceController(context)); 712 controllers.add(new SystemServerHeapDumpPreferenceController(context)); 713 controllers.add(new DevelopmentMemtagPagePreferenceController(context)); 714 controllers.add(new LocalBackupPasswordPreferenceController(context)); 715 controllers.add(new StayAwakePreferenceController(context, lifecycle)); 716 controllers.add(new HdcpCheckingPreferenceController(context)); 717 controllers.add(new BluetoothSnoopLogPreferenceController(context, fragment)); 718 controllers.add(new BluetoothStackLogPreferenceController(context)); 719 controllers.add(new DefaultLaunchPreferenceController(context, 720 "snoop_logger_filters_dashboard")); 721 controllers.add(new BluetoothSnoopLogFilterProfilePbapPreferenceController(context)); 722 controllers.add(new BluetoothSnoopLogFilterProfileMapPreferenceController(context)); 723 controllers.add(new OemUnlockPreferenceController(context, activity, fragment)); 724 controllers.add(new Enable16kPagesPreferenceController(context, fragment)); 725 controllers.add(new PictureColorModePreferenceController(context, lifecycle)); 726 controllers.add(new WebViewAppPreferenceController(context)); 727 controllers.add(new WebViewDevUiPreferenceController(context)); 728 controllers.add(new CoolColorTemperaturePreferenceController(context)); 729 controllers.add(new DisableAutomaticUpdatesPreferenceController(context)); 730 controllers.add(new SelectDSUPreferenceController(context)); 731 controllers.add(new AdbPreferenceController(context, fragment)); 732 controllers.add(new ClearAdbKeysPreferenceController(context, fragment)); 733 controllers.add(new WirelessDebuggingPreferenceController(context, lifecycle)); 734 controllers.add(new AdbAuthorizationTimeoutPreferenceController(context)); 735 controllers.add(new LocalTerminalPreferenceController(context)); 736 controllers.add(new LinuxTerminalPreferenceController(context)); 737 controllers.add(new BugReportInPowerPreferenceController(context)); 738 controllers.add(new AutomaticSystemServerHeapDumpPreferenceController(context)); 739 controllers.add(new MockLocationAppPreferenceController(context, fragment)); 740 controllers.add(new MockModemPreferenceController(context)); 741 controllers.add(new DebugViewAttributesPreferenceController(context)); 742 controllers.add(new SelectDebugAppPreferenceController(context, fragment)); 743 controllers.add(new WaitForDebuggerPreferenceController(context)); 744 controllers.add(new EnableGpuDebugLayersPreferenceController(context)); 745 controllers.add(new GraphicsDriverEnableAngleAsSystemDriverController(context, fragment)); 746 controllers.add(new ForcePeakRefreshRatePreferenceController(context)); 747 controllers.add(new EnableVerboseVendorLoggingPreferenceController(context)); 748 controllers.add(new VerifyAppsOverUsbPreferenceController(context)); 749 controllers.add(new ArtVerifierPreferenceController(context)); 750 controllers.add(new LogdSizePreferenceController(context)); 751 controllers.add(new LogPersistPreferenceController(context, fragment, lifecycle)); 752 controllers.add(new CameraLaserSensorPreferenceController(context)); 753 controllers.add(new WifiDisplayCertificationPreferenceController(context)); 754 controllers.add(new WifiVerboseLoggingPreferenceController(context)); 755 controllers.add(new WifiScanThrottlingPreferenceController(context)); 756 controllers.add(new WifiNonPersistentMacRandomizationPreferenceController(context)); 757 controllers.add(new MobileDataAlwaysOnPreferenceController(context)); 758 controllers.add(new TetheringHardwareAccelPreferenceController(context)); 759 controllers.add(new BluetoothDeviceNoNamePreferenceController(context)); 760 controllers.add(new BluetoothAbsoluteVolumePreferenceController(context)); 761 controllers.add(new BluetoothAvrcpVersionPreferenceController(context)); 762 controllers.add(new BluetoothMapVersionPreferenceController(context)); 763 controllers.add(new BluetoothLeAudioPreferenceController(context, fragment)); 764 controllers.add(new BluetoothLeAudioModePreferenceController(context, fragment)); 765 controllers.add(new BluetoothLeAudioUiPreferenceController(context, fragment)); 766 controllers.add(new BluetoothLeAudioDeviceDetailsPreferenceController(context)); 767 controllers.add(new BluetoothLeAudioAllowListPreferenceController(context)); 768 controllers.add(new BluetoothA2dpHwOffloadPreferenceController(context, fragment)); 769 controllers.add(new BluetoothLeAudioHwOffloadPreferenceController(context, fragment)); 770 controllers.add(new BluetoothMaxConnectedAudioDevicesPreferenceController(context)); 771 controllers.add(new NfcSnoopLogPreferenceController(context, fragment)); 772 controllers.add(new NfcVerboseVendorLogPreferenceController(context, fragment)); 773 controllers.add(new ShowTapsPreferenceController(context)); 774 controllers.add(new PointerLocationPreferenceController(context)); 775 controllers.add(new ShowKeyPressesPreferenceController(context)); 776 controllers.add(new TouchpadVisualizerPreferenceController(context)); 777 controllers.add(new ShowSurfaceUpdatesPreferenceController(context)); 778 controllers.add(new ShowLayoutBoundsPreferenceController(context)); 779 controllers.add(new ShowHdrSdrRatioPreferenceController(context)); 780 controllers.add(new ShowRefreshRatePreferenceController(context)); 781 controllers.add(new RtlLayoutPreferenceController(context)); 782 controllers.add(new WindowAnimationScalePreferenceController(context)); 783 controllers.add(new EmulateDisplayCutoutPreferenceController(context)); 784 controllers.add(new TransparentNavigationBarPreferenceController(context)); 785 controllers.add(new TransitionAnimationScalePreferenceController(context)); 786 controllers.add(new AnimatorDurationScalePreferenceController(context)); 787 controllers.add(new SecondaryDisplayPreferenceController(context)); 788 controllers.add(new GpuViewUpdatesPreferenceController(context)); 789 controllers.add(new HardwareLayersUpdatesPreferenceController(context)); 790 controllers.add(new DebugGpuOverdrawPreferenceController(context)); 791 controllers.add(new DebugNonRectClipOperationsPreferenceController(context)); 792 controllers.add(new GameDefaultFrameRatePreferenceController(context)); 793 controllers.add(new ForceDarkPreferenceController(context)); 794 controllers.add(new EnableBlursPreferenceController(context)); 795 controllers.add(new ForceMSAAPreferenceController(context)); 796 controllers.add(new HardwareOverlaysPreferenceController(context)); 797 controllers.add(new SimulateColorSpacePreferenceController(context)); 798 controllers.add(new UsbAudioRoutingPreferenceController(context)); 799 controllers.add(new StrictModePreferenceController(context)); 800 controllers.add(new ProfileGpuRenderingPreferenceController(context)); 801 controllers.add(new KeepActivitiesPreferenceController(context)); 802 controllers.add(new BackgroundProcessLimitPreferenceController(context)); 803 controllers.add(new CachedAppsFreezerPreferenceController(context)); 804 controllers.add(new ShowFirstCrashDialogPreferenceController(context)); 805 controllers.add(new AppsNotRespondingPreferenceController(context)); 806 controllers.add(new NotificationChannelWarningsPreferenceController(context)); 807 controllers.add(new AllowAppsOnExternalPreferenceController(context)); 808 controllers.add(new ResizableActivityPreferenceController(context)); 809 controllers.add(new FreeformWindowsPreferenceController(context, fragment)); 810 controllers.add(new DesktopModePreferenceController(context, fragment)); 811 controllers.add(new DesktopModeSecondaryDisplayPreferenceController(context, fragment)); 812 controllers.add(new DesktopExperiencePreferenceController(context, fragment)); 813 controllers.add(new NonResizableMultiWindowPreferenceController(context)); 814 controllers.add(new ShortcutManagerThrottlingPreferenceController(context)); 815 controllers.add(new EnableGnssRawMeasFullTrackingPreferenceController(context)); 816 controllers.add(new DefaultLaunchPreferenceController(context, "running_apps")); 817 controllers.add(new DefaultLaunchPreferenceController(context, "demo_mode")); 818 controllers.add(new DefaultLaunchPreferenceController(context, "quick_settings_tiles")); 819 controllers.add(new DefaultLaunchPreferenceController(context, "feature_flags_dashboard")); 820 controllers.add(new DefaultUsbConfigurationPreferenceController(context)); 821 controllers.add(new DefaultLaunchPreferenceController(context, "density")); 822 controllers.add(new DefaultLaunchPreferenceController(context, "background_check")); 823 controllers.add(new DefaultLaunchPreferenceController(context, "inactive_apps")); 824 controllers.add(new AutofillCategoryController(context, lifecycle)); 825 controllers.add(new AutofillLoggingLevelPreferenceController(context, lifecycle)); 826 controllers.add(new AutofillResetOptionsPreferenceController(context)); 827 controllers.add( 828 new BluetoothCodecListPreferenceController( 829 context, lifecycle, bluetoothA2dpConfigStore, fragment)); 830 controllers.add(new BluetoothSampleRateDialogPreferenceController(context, lifecycle, 831 bluetoothA2dpConfigStore)); 832 controllers.add(new BluetoothBitPerSampleDialogPreferenceController(context, lifecycle, 833 bluetoothA2dpConfigStore)); 834 controllers.add(new BluetoothQualityDialogPreferenceController(context, lifecycle, 835 bluetoothA2dpConfigStore)); 836 controllers.add(new BluetoothChannelModeDialogPreferenceController(context, lifecycle, 837 bluetoothA2dpConfigStore)); 838 controllers.add(new BluetoothHDAudioPreferenceController(context, lifecycle, 839 bluetoothA2dpConfigStore, fragment)); 840 controllers.add(new SharedDataPreferenceController(context)); 841 controllers.add(new OverlaySettingsPreferenceController(context)); 842 controllers.add(new StylusHandwritingPreferenceController(context)); 843 controllers.add(new IngressRateLimitPreferenceController((context))); 844 controllers.add(new PhantomProcessPreferenceController(context)); 845 controllers.add(new ForceEnableNotesRolePreferenceController(context)); 846 controllers.add(new GrammaticalGenderPreferenceController(context)); 847 controllers.add(new SensitiveContentProtectionPreferenceController(context)); 848 controllers.add(new ShadeDisplayAwarenessPreferenceController(context)); 849 850 return controllers; 851 } 852 853 @VisibleForTesting getDevelopmentOptionsController(Class<T> clazz)854 <T extends AbstractPreferenceController> T getDevelopmentOptionsController(Class<T> clazz) { 855 return use(clazz); 856 } 857 858 @Override onBluetoothCodecChanged()859 public void onBluetoothCodecChanged() { 860 for (AbstractPreferenceController controller : mPreferenceControllers) { 861 if (controller instanceof AbstractBluetoothDialogPreferenceController) { 862 ((AbstractBluetoothDialogPreferenceController) controller) 863 .onBluetoothCodecUpdated(); 864 } 865 } 866 } 867 868 @Override onBluetoothHDAudioEnabled(boolean enabled)869 public void onBluetoothHDAudioEnabled(boolean enabled) { 870 for (AbstractPreferenceController controller : mPreferenceControllers) { 871 if (controller instanceof AbstractBluetoothDialogPreferenceController) { 872 ((AbstractBluetoothDialogPreferenceController) controller).onHDAudioEnabled( 873 enabled); 874 } 875 if (controller instanceof BluetoothCodecListPreferenceController) { 876 ((BluetoothCodecListPreferenceController) controller).onHDAudioEnabled(enabled); 877 } 878 } 879 } 880 881 @Override onBroadcastDisabled()882 public void onBroadcastDisabled() { 883 for (AbstractPreferenceController controller : mPreferenceControllers) { 884 if (controller instanceof BluetoothLeAudioUiPreferenceController) { 885 ((BluetoothLeAudioUiPreferenceController) controller).onBroadcastDisabled(); 886 } 887 } 888 } 889 890 /** 891 * For Search. 892 */ 893 public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = 894 new BaseSearchIndexProvider(R.xml.development_settings) { 895 896 @Override 897 protected boolean isPageSearchEnabled(Context context) { 898 return DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(context); 899 } 900 901 @Override 902 public List<AbstractPreferenceController> createPreferenceControllers(Context 903 context) { 904 return buildPreferenceControllers(context, null /* activity */, 905 null /* lifecycle */, null /* devOptionsDashboardFragment */, 906 null /* bluetoothA2dpConfigStore */); 907 } 908 }; 909 } 910