1 /* 2 * Copyright (C) 2014 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; 18 19 import android.app.ActionBar; 20 import android.app.ActivityManager; 21 import android.content.BroadcastReceiver; 22 import android.content.ComponentName; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.content.IntentFilter; 26 import android.content.SharedPreferences; 27 import android.content.pm.ActivityInfo; 28 import android.content.pm.PackageManager; 29 import android.content.pm.PackageManager.NameNotFoundException; 30 import android.content.res.Resources.Theme; 31 import android.os.AsyncTask; 32 import android.os.Bundle; 33 import android.os.UserHandle; 34 import android.os.UserManager; 35 import android.text.TextUtils; 36 import android.util.Log; 37 import android.view.View; 38 import android.widget.Button; 39 40 import androidx.annotation.Nullable; 41 import androidx.annotation.VisibleForTesting; 42 import androidx.fragment.app.Fragment; 43 import androidx.fragment.app.FragmentManager; 44 import androidx.fragment.app.FragmentTransaction; 45 import androidx.localbroadcastmanager.content.LocalBroadcastManager; 46 import androidx.preference.Preference; 47 import androidx.preference.PreferenceFragmentCompat; 48 import androidx.preference.PreferenceManager; 49 50 import com.android.internal.util.ArrayUtils; 51 import com.android.settings.Settings.WifiSettingsActivity; 52 import com.android.settings.applications.manageapplications.ManageApplications; 53 import com.android.settings.backup.UserBackupSettingsActivity; 54 import com.android.settings.core.OnActivityResultListener; 55 import com.android.settings.core.SettingsBaseActivity; 56 import com.android.settings.core.SubSettingLauncher; 57 import com.android.settings.core.gateway.SettingsGateway; 58 import com.android.settings.dashboard.DashboardFeatureProvider; 59 import com.android.settings.homepage.TopLevelSettings; 60 import com.android.settings.overlay.FeatureFactory; 61 import com.android.settings.wfd.WifiDisplaySettings; 62 import com.android.settings.widget.SwitchBar; 63 import com.android.settingslib.core.instrumentation.Instrumentable; 64 import com.android.settingslib.core.instrumentation.SharedPreferencesLogger; 65 import com.android.settingslib.development.DevelopmentSettingsEnabler; 66 import com.android.settingslib.drawer.DashboardCategory; 67 68 import com.google.android.setupcompat.util.WizardManagerHelper; 69 70 import java.util.ArrayList; 71 import java.util.List; 72 73 74 public class SettingsActivity extends SettingsBaseActivity 75 implements PreferenceManager.OnPreferenceTreeClickListener, 76 PreferenceFragmentCompat.OnPreferenceStartFragmentCallback, 77 ButtonBarHandler, FragmentManager.OnBackStackChangedListener { 78 79 private static final String LOG_TAG = "SettingsActivity"; 80 81 // Constants for state save/restore 82 private static final String SAVE_KEY_CATEGORIES = ":settings:categories"; 83 84 /** 85 * When starting this activity, the invoking Intent can contain this extra 86 * string to specify which fragment should be initially displayed. 87 * <p/>Starting from Key Lime Pie, when this argument is passed in, the activity 88 * will call isValidFragment() to confirm that the fragment class name is valid for this 89 * activity. 90 */ 91 public static final String EXTRA_SHOW_FRAGMENT = ":settings:show_fragment"; 92 93 /** 94 * When starting this activity and using {@link #EXTRA_SHOW_FRAGMENT}, 95 * this extra can also be specified to supply a Bundle of arguments to pass 96 * to that fragment when it is instantiated during the initial creation 97 * of the activity. 98 */ 99 public static final String EXTRA_SHOW_FRAGMENT_ARGUMENTS = ":settings:show_fragment_args"; 100 101 /** 102 * Fragment "key" argument passed thru {@link #EXTRA_SHOW_FRAGMENT_ARGUMENTS} 103 */ 104 public static final String EXTRA_FRAGMENT_ARG_KEY = ":settings:fragment_args_key"; 105 106 // extras that allow any preference activity to be launched as part of a wizard 107 108 // show Back and Next buttons? takes boolean parameter 109 // Back will then return RESULT_CANCELED and Next RESULT_OK 110 protected static final String EXTRA_PREFS_SHOW_BUTTON_BAR = "extra_prefs_show_button_bar"; 111 112 // add a Skip button? 113 private static final String EXTRA_PREFS_SHOW_SKIP = "extra_prefs_show_skip"; 114 115 // specify custom text for the Back or Next buttons, or cause a button to not appear 116 // at all by setting it to null 117 protected static final String EXTRA_PREFS_SET_NEXT_TEXT = "extra_prefs_set_next_text"; 118 protected static final String EXTRA_PREFS_SET_BACK_TEXT = "extra_prefs_set_back_text"; 119 120 /** 121 * When starting this activity and using {@link #EXTRA_SHOW_FRAGMENT}, 122 * those extra can also be specify to supply the title or title res id to be shown for 123 * that fragment. 124 */ 125 public static final String EXTRA_SHOW_FRAGMENT_TITLE = ":settings:show_fragment_title"; 126 /** 127 * The package name used to resolve the title resource id. 128 */ 129 public static final String EXTRA_SHOW_FRAGMENT_TITLE_RES_PACKAGE_NAME = 130 ":settings:show_fragment_title_res_package_name"; 131 public static final String EXTRA_SHOW_FRAGMENT_TITLE_RESID = 132 ":settings:show_fragment_title_resid"; 133 134 public static final String EXTRA_SHOW_FRAGMENT_AS_SUBSETTING = 135 ":settings:show_fragment_as_subsetting"; 136 137 public static final String META_DATA_KEY_FRAGMENT_CLASS = 138 "com.android.settings.FRAGMENT_CLASS"; 139 140 private static final String EXTRA_UI_OPTIONS = "settings:ui_options"; 141 142 private String mFragmentClass; 143 144 private CharSequence mInitialTitle; 145 private int mInitialTitleResId; 146 147 private BroadcastReceiver mDevelopmentSettingsListener; 148 149 private boolean mBatteryPresent = true; 150 private BroadcastReceiver mBatteryInfoReceiver = new BroadcastReceiver() { 151 @Override 152 public void onReceive(Context context, Intent intent) { 153 String action = intent.getAction(); 154 if (Intent.ACTION_BATTERY_CHANGED.equals(action)) { 155 boolean batteryPresent = Utils.isBatteryPresent(intent); 156 157 if (mBatteryPresent != batteryPresent) { 158 mBatteryPresent = batteryPresent; 159 updateTilesList(); 160 } 161 } 162 } 163 }; 164 165 private SwitchBar mSwitchBar; 166 167 private Button mNextButton; 168 169 // Categories 170 private ArrayList<DashboardCategory> mCategories = new ArrayList<>(); 171 172 private DashboardFeatureProvider mDashboardFeatureProvider; 173 getSwitchBar()174 public SwitchBar getSwitchBar() { 175 return mSwitchBar; 176 } 177 178 @Override onPreferenceStartFragment(PreferenceFragmentCompat caller, Preference pref)179 public boolean onPreferenceStartFragment(PreferenceFragmentCompat caller, Preference pref) { 180 new SubSettingLauncher(this) 181 .setDestination(pref.getFragment()) 182 .setArguments(pref.getExtras()) 183 .setSourceMetricsCategory(caller instanceof Instrumentable 184 ? ((Instrumentable) caller).getMetricsCategory() 185 : Instrumentable.METRICS_CATEGORY_UNKNOWN) 186 .setTitleRes(-1) 187 .launch(); 188 return true; 189 } 190 191 @Override onPreferenceTreeClick(Preference preference)192 public boolean onPreferenceTreeClick(Preference preference) { 193 return false; 194 } 195 196 @Override getSharedPreferences(String name, int mode)197 public SharedPreferences getSharedPreferences(String name, int mode) { 198 if (name.equals(getPackageName() + "_preferences")) { 199 return new SharedPreferencesLogger(this, getMetricsTag(), 200 FeatureFactory.getFactory(this).getMetricsFeatureProvider()); 201 } 202 return super.getSharedPreferences(name, mode); 203 } 204 getMetricsTag()205 private String getMetricsTag() { 206 String tag = getClass().getName(); 207 if (getIntent() != null && getIntent().hasExtra(EXTRA_SHOW_FRAGMENT)) { 208 tag = getIntent().getStringExtra(EXTRA_SHOW_FRAGMENT); 209 } 210 if (tag.startsWith("com.android.settings.")) { 211 tag = tag.replace("com.android.settings.", ""); 212 } 213 return tag; 214 } 215 216 @Override onCreate(Bundle savedState)217 protected void onCreate(Bundle savedState) { 218 super.onCreate(savedState); 219 Log.d(LOG_TAG, "Starting onCreate"); 220 long startTime = System.currentTimeMillis(); 221 222 final FeatureFactory factory = FeatureFactory.getFactory(this); 223 224 mDashboardFeatureProvider = factory.getDashboardFeatureProvider(this); 225 226 // Should happen before any call to getIntent() 227 getMetaData(); 228 229 final Intent intent = getIntent(); 230 if (intent.hasExtra(EXTRA_UI_OPTIONS)) { 231 getWindow().setUiOptions(intent.getIntExtra(EXTRA_UI_OPTIONS, 0)); 232 } 233 234 // Getting Intent properties can only be done after the super.onCreate(...) 235 final String initialFragmentName = intent.getStringExtra(EXTRA_SHOW_FRAGMENT); 236 237 // This is a "Sub Settings" when: 238 // - this is a real SubSettings 239 // - or :settings:show_fragment_as_subsetting is passed to the Intent 240 final boolean isSubSettings = this instanceof SubSettings || 241 intent.getBooleanExtra(EXTRA_SHOW_FRAGMENT_AS_SUBSETTING, false); 242 243 // If this is a sub settings, then apply the SubSettings Theme for the ActionBar content 244 // insets. 245 // If this is in setup flow, don't apply theme. Because light theme needs to be applied 246 // in SettingsBaseActivity#onCreate(). 247 if (isSubSettings && !WizardManagerHelper.isAnySetupWizard(getIntent())) { 248 setTheme(R.style.Theme_SubSettings); 249 } 250 251 setContentView(R.layout.settings_main_prefs); 252 253 getSupportFragmentManager().addOnBackStackChangedListener(this); 254 255 if (savedState != null) { 256 // We are restarting from a previous saved state; used that to initialize, instead 257 // of starting fresh. 258 setTitleFromIntent(intent); 259 260 ArrayList<DashboardCategory> categories = 261 savedState.getParcelableArrayList(SAVE_KEY_CATEGORIES); 262 if (categories != null) { 263 mCategories.clear(); 264 mCategories.addAll(categories); 265 setTitleFromBackStack(); 266 } 267 } else { 268 launchSettingFragment(initialFragmentName, intent); 269 } 270 271 final boolean deviceProvisioned = Utils.isDeviceProvisioned(this); 272 273 final ActionBar actionBar = getActionBar(); 274 if (actionBar != null) { 275 actionBar.setDisplayHomeAsUpEnabled(deviceProvisioned); 276 actionBar.setHomeButtonEnabled(deviceProvisioned); 277 actionBar.setDisplayShowTitleEnabled(true); 278 } 279 mSwitchBar = findViewById(R.id.switch_bar); 280 if (mSwitchBar != null) { 281 mSwitchBar.setMetricsTag(getMetricsTag()); 282 } 283 284 // see if we should show Back/Next buttons 285 if (intent.getBooleanExtra(EXTRA_PREFS_SHOW_BUTTON_BAR, false)) { 286 287 View buttonBar = findViewById(R.id.button_bar); 288 if (buttonBar != null) { 289 buttonBar.setVisibility(View.VISIBLE); 290 291 Button backButton = findViewById(R.id.back_button); 292 backButton.setOnClickListener(v -> { 293 setResult(RESULT_CANCELED, null); 294 finish(); 295 }); 296 Button skipButton = findViewById(R.id.skip_button); 297 skipButton.setOnClickListener(v -> { 298 setResult(RESULT_OK, null); 299 finish(); 300 }); 301 mNextButton = findViewById(R.id.next_button); 302 mNextButton.setOnClickListener(v -> { 303 setResult(RESULT_OK, null); 304 finish(); 305 }); 306 307 // set our various button parameters 308 if (intent.hasExtra(EXTRA_PREFS_SET_NEXT_TEXT)) { 309 String buttonText = intent.getStringExtra(EXTRA_PREFS_SET_NEXT_TEXT); 310 if (TextUtils.isEmpty(buttonText)) { 311 mNextButton.setVisibility(View.GONE); 312 } else { 313 mNextButton.setText(buttonText); 314 } 315 } 316 if (intent.hasExtra(EXTRA_PREFS_SET_BACK_TEXT)) { 317 String buttonText = intent.getStringExtra(EXTRA_PREFS_SET_BACK_TEXT); 318 if (TextUtils.isEmpty(buttonText)) { 319 backButton.setVisibility(View.GONE); 320 } else { 321 backButton.setText(buttonText); 322 } 323 } 324 if (intent.getBooleanExtra(EXTRA_PREFS_SHOW_SKIP, false)) { 325 skipButton.setVisibility(View.VISIBLE); 326 } 327 } 328 } 329 330 if (DEBUG_TIMING) { 331 Log.d(LOG_TAG, "onCreate took " + (System.currentTimeMillis() - startTime) + " ms"); 332 } 333 } 334 335 @Override onApplyThemeResource(Theme theme, int resid, boolean first)336 protected void onApplyThemeResource(Theme theme, int resid, boolean first) { 337 theme.applyStyle(R.style.SetupWizardPartnerResource, true); 338 super.onApplyThemeResource(theme, resid, first); 339 } 340 341 @Override onActivityResult(int requestCode, int resultCode, @Nullable Intent data)342 protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { 343 super.onActivityResult(requestCode, resultCode, data); 344 final List<Fragment> fragments = getSupportFragmentManager().getFragments(); 345 if (fragments != null) { 346 for (Fragment fragment : fragments) { 347 if (fragment instanceof OnActivityResultListener) { 348 fragment.onActivityResult(requestCode, resultCode, data); 349 } 350 } 351 } 352 } 353 354 @VisibleForTesting launchSettingFragment(String initialFragmentName, Intent intent)355 void launchSettingFragment(String initialFragmentName, Intent intent) { 356 if (initialFragmentName != null) { 357 setTitleFromIntent(intent); 358 359 Bundle initialArguments = intent.getBundleExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS); 360 switchToFragment(initialFragmentName, initialArguments, true, 361 mInitialTitleResId, mInitialTitle); 362 } else { 363 // Show search icon as up affordance if we are displaying the main Dashboard 364 mInitialTitleResId = R.string.dashboard_title; 365 switchToFragment(TopLevelSettings.class.getName(), null /* args */, false, 366 mInitialTitleResId, mInitialTitle); 367 } 368 } 369 setTitleFromIntent(Intent intent)370 private void setTitleFromIntent(Intent intent) { 371 Log.d(LOG_TAG, "Starting to set activity title"); 372 final int initialTitleResId = intent.getIntExtra(EXTRA_SHOW_FRAGMENT_TITLE_RESID, -1); 373 if (initialTitleResId > 0) { 374 mInitialTitle = null; 375 mInitialTitleResId = initialTitleResId; 376 377 final String initialTitleResPackageName = intent.getStringExtra( 378 EXTRA_SHOW_FRAGMENT_TITLE_RES_PACKAGE_NAME); 379 if (initialTitleResPackageName != null) { 380 try { 381 Context authContext = createPackageContextAsUser(initialTitleResPackageName, 382 0 /* flags */, new UserHandle(UserHandle.myUserId())); 383 mInitialTitle = authContext.getResources().getText(mInitialTitleResId); 384 setTitle(mInitialTitle); 385 mInitialTitleResId = -1; 386 return; 387 } catch (NameNotFoundException e) { 388 Log.w(LOG_TAG, "Could not find package" + initialTitleResPackageName); 389 } 390 } else { 391 setTitle(mInitialTitleResId); 392 } 393 } else { 394 mInitialTitleResId = -1; 395 final String initialTitle = intent.getStringExtra(EXTRA_SHOW_FRAGMENT_TITLE); 396 mInitialTitle = (initialTitle != null) ? initialTitle : getTitle(); 397 setTitle(mInitialTitle); 398 } 399 Log.d(LOG_TAG, "Done setting title"); 400 } 401 402 @Override onBackStackChanged()403 public void onBackStackChanged() { 404 setTitleFromBackStack(); 405 } 406 setTitleFromBackStack()407 private void setTitleFromBackStack() { 408 final int count = getSupportFragmentManager().getBackStackEntryCount(); 409 410 if (count == 0) { 411 if (mInitialTitleResId > 0) { 412 setTitle(mInitialTitleResId); 413 } else { 414 setTitle(mInitialTitle); 415 } 416 return; 417 } 418 419 FragmentManager.BackStackEntry bse = getSupportFragmentManager(). 420 getBackStackEntryAt(count - 1); 421 setTitleFromBackStackEntry(bse); 422 } 423 setTitleFromBackStackEntry(FragmentManager.BackStackEntry bse)424 private void setTitleFromBackStackEntry(FragmentManager.BackStackEntry bse) { 425 final CharSequence title; 426 final int titleRes = bse.getBreadCrumbTitleRes(); 427 if (titleRes > 0) { 428 title = getText(titleRes); 429 } else { 430 title = bse.getBreadCrumbTitle(); 431 } 432 if (title != null) { 433 setTitle(title); 434 } 435 } 436 437 @Override onSaveInstanceState(Bundle outState)438 protected void onSaveInstanceState(Bundle outState) { 439 super.onSaveInstanceState(outState); 440 saveState(outState); 441 } 442 443 /** 444 * For testing purposes to avoid crashes from final variables in Activity's onSaveInstantState. 445 */ 446 @VisibleForTesting saveState(Bundle outState)447 void saveState(Bundle outState) { 448 if (mCategories.size() > 0) { 449 outState.putParcelableArrayList(SAVE_KEY_CATEGORIES, mCategories); 450 } 451 } 452 453 @Override onResume()454 protected void onResume() { 455 super.onResume(); 456 457 mDevelopmentSettingsListener = new BroadcastReceiver() { 458 @Override 459 public void onReceive(Context context, Intent intent) { 460 updateTilesList(); 461 } 462 }; 463 LocalBroadcastManager.getInstance(this).registerReceiver(mDevelopmentSettingsListener, 464 new IntentFilter(DevelopmentSettingsEnabler.DEVELOPMENT_SETTINGS_CHANGED_ACTION)); 465 466 registerReceiver(mBatteryInfoReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); 467 468 updateTilesList(); 469 } 470 471 @Override onPause()472 protected void onPause() { 473 super.onPause(); 474 LocalBroadcastManager.getInstance(this).unregisterReceiver(mDevelopmentSettingsListener); 475 mDevelopmentSettingsListener = null; 476 unregisterReceiver(mBatteryInfoReceiver); 477 } 478 479 @Override setTaskDescription(ActivityManager.TaskDescription taskDescription)480 public void setTaskDescription(ActivityManager.TaskDescription taskDescription) { 481 taskDescription.setIcon(R.drawable.ic_launcher_settings); 482 super.setTaskDescription(taskDescription); 483 } 484 isValidFragment(String fragmentName)485 protected boolean isValidFragment(String fragmentName) { 486 // Almost all fragments are wrapped in this, 487 // except for a few that have their own activities. 488 for (int i = 0; i < SettingsGateway.ENTRY_FRAGMENTS.length; i++) { 489 if (SettingsGateway.ENTRY_FRAGMENTS[i].equals(fragmentName)) return true; 490 } 491 return false; 492 } 493 494 @Override getIntent()495 public Intent getIntent() { 496 Intent superIntent = super.getIntent(); 497 String startingFragment = getStartingFragmentClass(superIntent); 498 // This is called from super.onCreate, isMultiPane() is not yet reliable 499 // Do not use onIsHidingHeaders either, which relies itself on this method 500 if (startingFragment != null) { 501 Intent modIntent = new Intent(superIntent); 502 modIntent.putExtra(EXTRA_SHOW_FRAGMENT, startingFragment); 503 Bundle args = superIntent.getBundleExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS); 504 if (args != null) { 505 args = new Bundle(args); 506 } else { 507 args = new Bundle(); 508 } 509 args.putParcelable("intent", superIntent); 510 modIntent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, args); 511 return modIntent; 512 } 513 return superIntent; 514 } 515 516 /** 517 * Checks if the component name in the intent is different from the Settings class and 518 * returns the class name to load as a fragment. 519 */ getStartingFragmentClass(Intent intent)520 private String getStartingFragmentClass(Intent intent) { 521 if (mFragmentClass != null) return mFragmentClass; 522 523 String intentClass = intent.getComponent().getClassName(); 524 if (intentClass.equals(getClass().getName())) return null; 525 526 if ("com.android.settings.RunningServices".equals(intentClass) 527 || "com.android.settings.applications.StorageUse".equals(intentClass)) { 528 // Old names of manage apps. 529 intentClass = ManageApplications.class.getName(); 530 } 531 532 return intentClass; 533 } 534 535 /** 536 * Called by a preference panel fragment to finish itself. 537 * 538 * @param resultCode Optional result code to send back to the original 539 * launching fragment. 540 * @param resultData Optional result data to send back to the original 541 * launching fragment. 542 */ finishPreferencePanel(int resultCode, Intent resultData)543 public void finishPreferencePanel(int resultCode, Intent resultData) { 544 setResult(resultCode, resultData); 545 finish(); 546 } 547 548 /** 549 * Switch to a specific Fragment with taking care of validation, Title and BackStack 550 */ switchToFragment(String fragmentName, Bundle args, boolean validate, int titleResId, CharSequence title)551 private Fragment switchToFragment(String fragmentName, Bundle args, boolean validate, 552 int titleResId, CharSequence title) { 553 Log.d(LOG_TAG, "Switching to fragment " + fragmentName); 554 if (validate && !isValidFragment(fragmentName)) { 555 throw new IllegalArgumentException("Invalid fragment for this activity: " 556 + fragmentName); 557 } 558 Fragment f = Fragment.instantiate(this, fragmentName, args); 559 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); 560 transaction.replace(R.id.main_content, f); 561 if (titleResId > 0) { 562 transaction.setBreadCrumbTitle(titleResId); 563 } else if (title != null) { 564 transaction.setBreadCrumbTitle(title); 565 } 566 transaction.commitAllowingStateLoss(); 567 getSupportFragmentManager().executePendingTransactions(); 568 Log.d(LOG_TAG, "Executed frag manager pendingTransactions"); 569 return f; 570 } 571 updateTilesList()572 private void updateTilesList() { 573 // Generally the items that are will be changing from these updates will 574 // not be in the top list of tiles, so run it in the background and the 575 // SettingsBaseActivity will pick up on the updates automatically. 576 AsyncTask.execute(new Runnable() { 577 @Override 578 public void run() { 579 doUpdateTilesList(); 580 } 581 }); 582 } 583 doUpdateTilesList()584 private void doUpdateTilesList() { 585 PackageManager pm = getPackageManager(); 586 final UserManager um = UserManager.get(this); 587 final boolean isAdmin = um.isAdminUser(); 588 boolean somethingChanged = false; 589 final String packageName = getPackageName(); 590 final StringBuilder changedList = new StringBuilder(); 591 somethingChanged = setTileEnabled(changedList, 592 new ComponentName(packageName, WifiSettingsActivity.class.getName()), 593 pm.hasSystemFeature(PackageManager.FEATURE_WIFI), isAdmin) || somethingChanged; 594 595 somethingChanged = setTileEnabled(changedList, new ComponentName(packageName, 596 Settings.BluetoothSettingsActivity.class.getName()), 597 pm.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH), isAdmin) 598 || somethingChanged; 599 600 // Enable DataUsageSummaryActivity if the data plan feature flag is turned on otherwise 601 // enable DataPlanUsageSummaryActivity. 602 somethingChanged = setTileEnabled(changedList, 603 new ComponentName(packageName, Settings.DataUsageSummaryActivity.class.getName()), 604 Utils.isBandwidthControlEnabled() /* enabled */, 605 isAdmin) || somethingChanged; 606 607 somethingChanged = setTileEnabled(changedList, 608 new ComponentName(packageName, 609 Settings.ConnectedDeviceDashboardActivity.class.getName()), 610 !UserManager.isDeviceInDemoMode(this) /* enabled */, 611 isAdmin) || somethingChanged; 612 613 somethingChanged = setTileEnabled(changedList, new ComponentName(packageName, 614 Settings.PowerUsageSummaryActivity.class.getName()), 615 mBatteryPresent, isAdmin) || somethingChanged; 616 617 somethingChanged = setTileEnabled(changedList, new ComponentName(packageName, 618 Settings.DataUsageSummaryActivity.class.getName()), 619 Utils.isBandwidthControlEnabled(), isAdmin) 620 || somethingChanged; 621 622 somethingChanged = setTileEnabled(changedList, new ComponentName(packageName, 623 Settings.UserSettingsActivity.class.getName()), 624 UserHandle.MU_ENABLED && UserManager.supportsMultipleUsers() 625 && !Utils.isMonkeyRunning(), isAdmin) 626 || somethingChanged; 627 628 final boolean showDev = DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(this) 629 && !Utils.isMonkeyRunning(); 630 somethingChanged = setTileEnabled(changedList, new ComponentName(packageName, 631 Settings.DevelopmentSettingsDashboardActivity.class.getName()), 632 showDev, isAdmin) 633 || somethingChanged; 634 635 somethingChanged = setTileEnabled(changedList, new ComponentName(packageName, 636 UserBackupSettingsActivity.class.getName()), true, isAdmin) 637 || somethingChanged; 638 639 somethingChanged = setTileEnabled(changedList, new ComponentName(packageName, 640 Settings.WifiDisplaySettingsActivity.class.getName()), 641 WifiDisplaySettings.isAvailable(this), isAdmin) 642 || somethingChanged; 643 644 if (UserHandle.MU_ENABLED && !isAdmin) { 645 646 // When on restricted users, disable all extra categories (but only the settings ones). 647 final List<DashboardCategory> categories = mDashboardFeatureProvider.getAllCategories(); 648 synchronized (categories) { 649 for (DashboardCategory category : categories) { 650 final int tileCount = category.getTilesCount(); 651 for (int i = 0; i < tileCount; i++) { 652 final ComponentName component = category.getTile(i) 653 .getIntent().getComponent(); 654 final String name = component.getClassName(); 655 final boolean isEnabledForRestricted = ArrayUtils.contains( 656 SettingsGateway.SETTINGS_FOR_RESTRICTED, name); 657 if (packageName.equals(component.getPackageName()) 658 && !isEnabledForRestricted) { 659 somethingChanged = 660 setTileEnabled(changedList, component, false, isAdmin) 661 || somethingChanged; 662 } 663 } 664 } 665 } 666 } 667 668 // Final step, refresh categories. 669 if (somethingChanged) { 670 Log.d(LOG_TAG, "Enabled state changed for some tiles, reloading all categories " 671 + changedList.toString()); 672 updateCategories(); 673 } else { 674 Log.d(LOG_TAG, "No enabled state changed, skipping updateCategory call"); 675 } 676 } 677 678 /** 679 * @return whether or not the enabled state actually changed. 680 */ setTileEnabled(StringBuilder changedList, ComponentName component, boolean enabled, boolean isAdmin)681 private boolean setTileEnabled(StringBuilder changedList, ComponentName component, 682 boolean enabled, boolean isAdmin) { 683 if (UserHandle.MU_ENABLED && !isAdmin && getPackageName().equals(component.getPackageName()) 684 && !ArrayUtils.contains(SettingsGateway.SETTINGS_FOR_RESTRICTED, 685 component.getClassName())) { 686 enabled = false; 687 } 688 boolean changed = setTileEnabled(component, enabled); 689 if (changed) { 690 changedList.append(component.toShortString()).append(","); 691 } 692 return changed; 693 } 694 getMetaData()695 private void getMetaData() { 696 try { 697 ActivityInfo ai = getPackageManager().getActivityInfo(getComponentName(), 698 PackageManager.GET_META_DATA); 699 if (ai == null || ai.metaData == null) return; 700 mFragmentClass = ai.metaData.getString(META_DATA_KEY_FRAGMENT_CLASS); 701 } catch (NameNotFoundException nnfe) { 702 // No recovery 703 Log.d(LOG_TAG, "Cannot get Metadata for: " + getComponentName().toString()); 704 } 705 } 706 707 // give subclasses access to the Next button hasNextButton()708 public boolean hasNextButton() { 709 return mNextButton != null; 710 } 711 getNextButton()712 public Button getNextButton() { 713 return mNextButton; 714 } 715 } 716