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 17package com.android.settings.development; 18 19import android.app.Activity; 20import android.bluetooth.BluetoothA2dp; 21import android.bluetooth.BluetoothAdapter; 22import android.bluetooth.BluetoothCodecStatus; 23import android.bluetooth.BluetoothProfile; 24import android.content.BroadcastReceiver; 25import android.content.Context; 26import android.content.Intent; 27import android.content.IntentFilter; 28import android.os.Bundle; 29import android.os.UserManager; 30import android.provider.SearchIndexableResource; 31import android.support.annotation.VisibleForTesting; 32import android.support.v4.content.LocalBroadcastManager; 33import android.util.Log; 34import android.view.LayoutInflater; 35import android.view.View; 36import android.view.ViewGroup; 37import android.widget.Switch; 38 39import com.android.internal.logging.nano.MetricsProto; 40import com.android.settings.R; 41import com.android.settings.SettingsActivity; 42import com.android.settings.Utils; 43import com.android.settings.dashboard.RestrictedDashboardFragment; 44import com.android.settings.search.BaseSearchIndexProvider; 45import com.android.settings.search.Indexable; 46import com.android.settings.widget.SwitchBar; 47import com.android.settingslib.core.AbstractPreferenceController; 48import com.android.settingslib.core.lifecycle.Lifecycle; 49import com.android.settingslib.development.DeveloperOptionsPreferenceController; 50import com.android.settingslib.development.DevelopmentSettingsEnabler; 51import com.android.settingslib.development.SystemPropPoker; 52 53import java.util.ArrayList; 54import java.util.Arrays; 55import java.util.List; 56 57public 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 134 public DevelopmentSettingsDashboardFragment() { 135 super(UserManager.DISALLOW_DEBUGGING_FEATURES); 136 } 137 138 @Override 139 public void onCreate(Bundle icicle) { 140 super.onCreate(icicle); 141 if (Utils.isMonkeyRunning()) { 142 getActivity().finish(); 143 return; 144 } 145 } 146 147 @Override 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 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 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 203 public int getMetricsCategory() { 204 return MetricsProto.MetricsEvent.DEVELOPMENT; 205 } 206 207 @Override 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 224 public void onOemUnlockDialogConfirmed() { 225 final OemUnlockPreferenceController controller = getDevelopmentOptionsController( 226 OemUnlockPreferenceController.class); 227 controller.onOemUnlockConfirmed(); 228 } 229 230 @Override 231 public void onOemUnlockDialogDismissed() { 232 final OemUnlockPreferenceController controller = getDevelopmentOptionsController( 233 OemUnlockPreferenceController.class); 234 controller.onOemUnlockDismissed(); 235 } 236 237 @Override 238 public void onEnableAdbDialogConfirmed() { 239 final AdbPreferenceController controller = getDevelopmentOptionsController( 240 AdbPreferenceController.class); 241 controller.onAdbDialogConfirmed(); 242 243 } 244 245 @Override 246 public void onEnableAdbDialogDismissed() { 247 final AdbPreferenceController controller = getDevelopmentOptionsController( 248 AdbPreferenceController.class); 249 controller.onAdbDialogDismissed(); 250 } 251 252 @Override 253 public void onAdbClearKeysDialogConfirmed() { 254 final ClearAdbKeysPreferenceController controller = getDevelopmentOptionsController( 255 ClearAdbKeysPreferenceController.class); 256 controller.onClearAdbKeysConfirmed(); 257 } 258 259 @Override 260 public void onDisableLogPersistDialogConfirmed() { 261 final LogPersistPreferenceController controller = getDevelopmentOptionsController( 262 LogPersistPreferenceController.class); 263 controller.onDisableLogPersistDialogConfirmed(); 264 } 265 266 @Override 267 public void onDisableLogPersistDialogRejected() { 268 final LogPersistPreferenceController controller = getDevelopmentOptionsController( 269 LogPersistPreferenceController.class); 270 controller.onDisableLogPersistDialogRejected(); 271 } 272 273 @Override 274 public void onA2dpHwDialogConfirmed() { 275 final BluetoothA2dpHwOffloadPreferenceController controller = 276 getDevelopmentOptionsController(BluetoothA2dpHwOffloadPreferenceController.class); 277 controller.onA2dpHwDialogConfirmed(); 278 } 279 280 @Override 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 298 protected String getLogTag() { 299 return TAG; 300 } 301 302 @Override 303 public int getHelpResource() { 304 return 0; 305 } 306 307 @Override 308 protected int getPreferenceScreenResId() { 309 return Utils.isMonkeyRunning()? R.xml.placeholder_prefs : R.xml.development_settings; 310 } 311 312 @Override 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 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 334 private void unregisterReceivers() { 335 LocalBroadcastManager.getInstance(getContext()).unregisterReceiver(mEnableAdbReceiver); 336 getActivity().unregisterReceiver(mBluetoothA2dpReceiver); 337 } 338 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 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 368 void onEnableDevelopmentOptionsConfirmed() { 369 enableDeveloperOptions(); 370 } 371 372 void onEnableDevelopmentOptionsRejected() { 373 // Reset the toggle 374 mSwitchBar.setChecked(false); 375 } 376 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 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