1 /* 2 * Copyright (C) 2015 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.tv.settings; 18 19 import static com.android.tv.settings.util.InstrumentationUtils.logEntrySelected; 20 import static com.android.tv.settings.util.InstrumentationUtils.logPageFocused; 21 22 import android.accounts.Account; 23 import android.accounts.AccountManager; 24 import android.app.tvsettings.TvSettingsEnums; 25 import android.bluetooth.BluetoothAdapter; 26 import android.bluetooth.BluetoothDevice; 27 import android.content.ActivityNotFoundException; 28 import android.content.BroadcastReceiver; 29 import android.content.ComponentName; 30 import android.content.Context; 31 import android.content.Intent; 32 import android.content.IntentFilter; 33 import android.content.pm.ApplicationInfo; 34 import android.content.pm.PackageManager; 35 import android.content.pm.ResolveInfo; 36 import android.content.res.Resources; 37 import android.graphics.drawable.Drawable; 38 import android.os.Bundle; 39 import android.service.settings.suggestions.Suggestion; 40 import android.telephony.SignalStrength; 41 import android.text.TextUtils; 42 import android.util.Log; 43 import android.view.LayoutInflater; 44 import android.view.View; 45 import android.view.ViewGroup; 46 47 import androidx.annotation.Keep; 48 import androidx.annotation.VisibleForTesting; 49 import androidx.preference.Preference; 50 import androidx.preference.PreferenceCategory; 51 import androidx.preference.SwitchPreference; 52 53 import com.android.settingslib.core.AbstractPreferenceController; 54 import com.android.settingslib.suggestions.SuggestionControllerMixin; 55 import com.android.settingslib.utils.IconCache; 56 import com.android.tv.settings.HotwordSwitchController.HotwordStateListener; 57 import com.android.tv.settings.accounts.AccountsFragment; 58 import com.android.tv.settings.connectivity.ConnectivityListener; 59 import com.android.tv.settings.overlay.FeatureFactory; 60 import com.android.tv.settings.suggestions.SuggestionPreference; 61 import com.android.tv.settings.system.SecurityFragment; 62 import com.android.tv.settings.util.SliceUtils; 63 import com.android.tv.twopanelsettings.TwoPanelSettingsFragment; 64 import com.android.tv.twopanelsettings.slices.SlicePreference; 65 66 import java.util.ArrayList; 67 import java.util.List; 68 import java.util.Set; 69 70 /** 71 * The fragment where all good things begin. Evil is handled elsewhere. 72 */ 73 @Keep 74 public class MainFragment extends PreferenceControllerFragment implements 75 SuggestionControllerMixin.SuggestionControllerHost, SuggestionPreference.Callback, 76 HotwordStateListener { 77 78 private static final String TAG = "MainFragment"; 79 private static final String KEY_SUGGESTIONS_LIST = "suggestions"; 80 @VisibleForTesting 81 static final String KEY_ACCOUNTS_AND_SIGN_IN = "accounts_and_sign_in"; 82 @VisibleForTesting 83 static final String KEY_ACCOUNTS_AND_SIGN_IN_SLICE = "accounts_and_sign_in_slice"; 84 private static final String KEY_APPLICATIONS = "applications"; 85 @VisibleForTesting 86 static final String KEY_ACCESSORIES = "remotes_and_accessories"; 87 @VisibleForTesting 88 static final String KEY_CONNECTED_DEVICES = "connected_devices"; 89 private static final String KEY_CONNECTED_DEVICES_SLICE = "connected_devices_slice"; 90 @VisibleForTesting 91 static final String KEY_NETWORK = "network"; 92 @VisibleForTesting 93 static final String KEY_SOUND = "sound"; 94 public static final String ACTION_SOUND = "com.android.tv.settings.SOUND"; 95 @VisibleForTesting 96 static final String ACTION_CONNECTED_DEVICES = "com.android.tv.settings.CONNECTED_DEVICES"; 97 @VisibleForTesting 98 static final String KEY_PRIVACY = "privacy"; 99 @VisibleForTesting 100 static final String KEY_DISPLAY_AND_SOUND = "display_and_sound"; 101 @VisibleForTesting 102 static final String KEY_QUICK_SETTINGS = "quick_settings"; 103 private static final String KEY_CHANNELS_AND_INPUTS = "channels_and_inputs"; 104 105 private static final String ACTION_ACCOUNTS = "com.android.tv.settings.ACCOUNTS"; 106 @VisibleForTesting 107 ConnectivityListener mConnectivityListener; 108 @VisibleForTesting 109 PreferenceCategory mSuggestionsList; 110 private SuggestionControllerMixin mSuggestionControllerMixin; 111 @VisibleForTesting 112 IconCache mIconCache; 113 @VisibleForTesting 114 BluetoothAdapter mBtAdapter; 115 @VisibleForTesting 116 boolean mHasBtAccessories; 117 @VisibleForTesting 118 boolean mHasAccounts; 119 120 /** Controllers for the Quick Settings section. */ 121 private List<AbstractPreferenceController> mPreferenceControllers; 122 private HotwordSwitchController mHotwordSwitchController; 123 private TakeBugReportController mTakeBugReportController; 124 private PreferenceCategory mQuickSettingsList; 125 private SwitchPreference mHotwordSwitch; 126 private Preference mTakeBugReportPreference; 127 128 private final BroadcastReceiver mBCMReceiver = new BroadcastReceiver() { 129 @Override 130 public void onReceive(Context context, Intent intent) { 131 updateAccessoryPref(); 132 } 133 }; 134 newInstance()135 public static MainFragment newInstance() { 136 return new MainFragment(); 137 } 138 139 @Override getMetricsCategory()140 public int getMetricsCategory() { 141 // Do not log visibility. 142 return METRICS_CATEGORY_UNKNOWN; 143 } 144 145 @Override getPreferenceScreenResId()146 protected int getPreferenceScreenResId() { 147 return R.xml.main_prefs; 148 } 149 150 @Override onCreate(Bundle savedInstanceState)151 public void onCreate(Bundle savedInstanceState) { 152 mIconCache = new IconCache(getContext()); 153 mConnectivityListener = 154 new ConnectivityListener(getContext(), this::updateConnectivity, getLifecycle()); 155 mBtAdapter = BluetoothAdapter.getDefaultAdapter(); 156 super.onCreate(savedInstanceState); 157 // This is to record the initial start of Settings root in two panel settings case, as the 158 // MainFragment is the left-most pane and will not be slided in from preview pane. For 159 // classic settings case, the event will be recorded in onResume() as this is an instance 160 // of SettingsPreferenceFragment. 161 if (getCallbackFragment() instanceof TwoPanelSettingsFragment) { 162 logPageFocused(getPageId(), true); 163 } 164 } 165 166 @Override onDestroy()167 public void onDestroy() { 168 if (mHotwordSwitchController != null) { 169 mHotwordSwitchController.unregister(); 170 } 171 super.onDestroy(); 172 } 173 174 /** @return true if there is at least one available item in quick settings. */ shouldShowQuickSettings()175 private boolean shouldShowQuickSettings() { 176 for (AbstractPreferenceController controller : mPreferenceControllers) { 177 if (controller.isAvailable()) { 178 return true; 179 } 180 } 181 return false; 182 } 183 showOrHideQuickSettings()184 private void showOrHideQuickSettings() { 185 if (shouldShowQuickSettings()) { 186 showQuickSettings(); 187 } else { 188 hideQuickSettings(); 189 } 190 } 191 192 @Override onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)193 public View onCreateView(LayoutInflater inflater, ViewGroup container, 194 Bundle savedInstanceState) { 195 showOrHideQuickSettings(); 196 updateAccountPref(); 197 updateAccessoryPref(); 198 updateConnectivity(); 199 return super.onCreateView(inflater, container, savedInstanceState); 200 } 201 202 /** Creates the quick settings category and its children. */ showQuickSettings()203 private void showQuickSettings() { 204 if (mQuickSettingsList != null) { 205 return; 206 } 207 mQuickSettingsList = new PreferenceCategory(this.getPreferenceManager().getContext()); 208 mQuickSettingsList.setKey(KEY_QUICK_SETTINGS); 209 mQuickSettingsList.setTitle(R.string.header_category_quick_settings); 210 mQuickSettingsList.setOrder(1); // at top, but below suggested settings 211 getPreferenceScreen().addPreference(mQuickSettingsList); 212 if (mHotwordSwitchController.isAvailable()) { 213 mHotwordSwitch = new SwitchPreference(this.getPreferenceManager().getContext()); 214 mHotwordSwitch.setKey(HotwordSwitchController.KEY_HOTWORD_SWITCH); 215 mHotwordSwitch.setOnPreferenceClickListener( 216 preference -> { 217 logEntrySelected(TvSettingsEnums.QUICK_SETTINGS); 218 return false; 219 } 220 ); 221 mHotwordSwitchController.updateState(mHotwordSwitch); 222 mQuickSettingsList.addPreference(mHotwordSwitch); 223 } 224 if (mTakeBugReportController.isAvailable()) { 225 mTakeBugReportPreference = new Preference(this.getPreferenceManager().getContext()); 226 mTakeBugReportPreference.setKey(TakeBugReportController.KEY_TAKE_BUG_REPORT); 227 mTakeBugReportPreference.setOnPreferenceClickListener( 228 preference -> { 229 logEntrySelected(TvSettingsEnums.QUICK_SETTINGS); 230 return false; 231 } 232 ); 233 mTakeBugReportController.updateState(mTakeBugReportPreference); 234 mQuickSettingsList.addPreference(mTakeBugReportPreference); 235 } 236 } 237 238 /** Removes the quick settings category and all its children. */ hideQuickSettings()239 private void hideQuickSettings() { 240 Preference quickSettingsPref = findPreference(KEY_QUICK_SETTINGS); 241 if (quickSettingsPref == null) { 242 return; 243 } 244 mQuickSettingsList.removeAll(); 245 getPreferenceScreen().removePreference(mQuickSettingsList); 246 mQuickSettingsList = null; 247 } 248 249 @Override onHotwordStateChanged()250 public void onHotwordStateChanged() { 251 if (mHotwordSwitch != null) { 252 mHotwordSwitchController.updateState(mHotwordSwitch); 253 } 254 showOrHideQuickSettings(); 255 } 256 257 @Override onHotwordEnable()258 public void onHotwordEnable() { 259 try { 260 Intent intent = new Intent(HotwordSwitchController.ACTION_HOTWORD_ENABLE); 261 intent.setPackage(HotwordSwitchController.ASSISTANT_PGK_NAME); 262 startActivityForResult(intent, 0); 263 } catch (ActivityNotFoundException e) { 264 Log.w(TAG, "Unable to find hotwording activity.", e); 265 } 266 } 267 268 @Override onHotwordDisable()269 public void onHotwordDisable() { 270 try { 271 Intent intent = new Intent(HotwordSwitchController.ACTION_HOTWORD_DISABLE); 272 intent.setPackage(HotwordSwitchController.ASSISTANT_PGK_NAME); 273 startActivityForResult(intent, 0); 274 } catch (ActivityNotFoundException e) { 275 Log.w(TAG, "Unable to find hotwording activity.", e); 276 } 277 } 278 279 @Override onCreatePreferences(Bundle savedInstanceState, String rootKey)280 public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { 281 setPreferencesFromResource(R.xml.main_prefs, null); 282 if (isRestricted()) { 283 Preference appPref = findPreference(KEY_APPLICATIONS); 284 if (appPref != null) { 285 appPref.setVisible(false); 286 } 287 Preference accountsPref = findPreference(KEY_ACCOUNTS_AND_SIGN_IN); 288 if (accountsPref != null) { 289 accountsPref.setVisible(false); 290 } 291 } 292 if (!supportBluetooth()) { 293 Preference accessoryPreference = findPreference(KEY_ACCESSORIES); 294 if (accessoryPreference != null) { 295 accessoryPreference.setVisible(false); 296 } 297 } 298 if (FeatureFactory.getFactory(getContext()).isTwoPanelLayout()) { 299 Preference displaySoundPref = findPreference(KEY_DISPLAY_AND_SOUND); 300 if (displaySoundPref != null) { 301 displaySoundPref.setVisible(true); 302 } 303 Preference privacyPref = findPreference(KEY_PRIVACY); 304 if (privacyPref != null) { 305 privacyPref.setVisible(true); 306 } 307 } 308 mHotwordSwitchController.init(this); 309 updateSoundSettings(); 310 } 311 312 @Override onCreatePreferenceControllers(Context context)313 protected List<AbstractPreferenceController> onCreatePreferenceControllers(Context context) { 314 mPreferenceControllers = new ArrayList<>(2); 315 mHotwordSwitchController = new HotwordSwitchController(context); 316 mTakeBugReportController = new TakeBugReportController(context); 317 mPreferenceControllers.add(mHotwordSwitchController); 318 mPreferenceControllers.add(mTakeBugReportController); 319 return mPreferenceControllers; 320 } 321 322 @VisibleForTesting updateConnectivity()323 void updateConnectivity() { 324 final Preference networkPref = findPreference(KEY_NETWORK); 325 if (networkPref == null) { 326 return; 327 } 328 329 if (mConnectivityListener.isCellConnected()) { 330 final int signal = mConnectivityListener.getCellSignalStrength(); 331 switch (signal) { 332 case SignalStrength.SIGNAL_STRENGTH_GREAT: 333 networkPref.setIcon(R.drawable.ic_cell_signal_4_white); 334 break; 335 case SignalStrength.SIGNAL_STRENGTH_GOOD: 336 networkPref.setIcon(R.drawable.ic_cell_signal_3_white); 337 break; 338 case SignalStrength.SIGNAL_STRENGTH_MODERATE: 339 networkPref.setIcon(R.drawable.ic_cell_signal_2_white); 340 break; 341 case SignalStrength.SIGNAL_STRENGTH_POOR: 342 networkPref.setIcon(R.drawable.ic_cell_signal_1_white); 343 break; 344 case SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN: 345 default: 346 networkPref.setIcon(R.drawable.ic_cell_signal_0_white); 347 break; 348 } 349 } else if (mConnectivityListener.isEthernetConnected()) { 350 networkPref.setIcon(R.drawable.ic_ethernet_white); 351 networkPref.setSummary(R.string.connectivity_summary_ethernet_connected); 352 } else if (mConnectivityListener.isWifiEnabledOrEnabling()) { 353 if (mConnectivityListener.isWifiConnected()) { 354 final int signal = mConnectivityListener.getWifiSignalStrength(5); 355 switch (signal) { 356 case 4: 357 networkPref.setIcon(R.drawable.ic_wifi_signal_4_white); 358 break; 359 case 3: 360 networkPref.setIcon(R.drawable.ic_wifi_signal_3_white); 361 break; 362 case 2: 363 networkPref.setIcon(R.drawable.ic_wifi_signal_2_white); 364 break; 365 case 1: 366 networkPref.setIcon(R.drawable.ic_wifi_signal_1_white); 367 break; 368 case 0: 369 default: 370 networkPref.setIcon(R.drawable.ic_wifi_signal_0_white); 371 break; 372 } 373 networkPref.setSummary(mConnectivityListener.getSsid()); 374 } else { 375 networkPref.setIcon(R.drawable.ic_wifi_not_connected); 376 networkPref.setSummary(R.string.connectivity_summary_no_network_connected); 377 } 378 } else { 379 networkPref.setIcon(R.drawable.ic_wifi_signal_off_white); 380 networkPref.setSummary(R.string.connectivity_summary_wifi_disabled); 381 } 382 } 383 384 @VisibleForTesting updateSoundSettings()385 void updateSoundSettings() { 386 final Preference soundPref = findPreference(KEY_SOUND); 387 if (soundPref != null) { 388 Intent soundIntent = new Intent(ACTION_SOUND); 389 final ResolveInfo info = systemIntentIsHandled(getContext(), soundIntent); 390 soundPref.setVisible(info != null); 391 if (info != null && info.activityInfo != null) { 392 String pkgName = info.activityInfo.packageName; 393 Drawable icon = getDrawableResource(pkgName, "sound_icon"); 394 if (icon != null) { 395 soundPref.setIcon(icon); 396 } 397 String title = getStringResource(pkgName, "sound_pref_title"); 398 if (!TextUtils.isEmpty(title)) { 399 soundPref.setTitle(title); 400 } 401 String summary = getStringResource(pkgName, "sound_pref_summary"); 402 if (!TextUtils.isEmpty(summary)) { 403 soundPref.setSummary(summary); 404 } 405 } 406 } 407 } 408 409 /** 410 * Extracts a string resource from a given package. 411 * 412 * @param pkgName the package name 413 * @param resource name, e.g. "my_string_name" 414 */ getStringResource(String pkgName, String resourceName)415 private String getStringResource(String pkgName, String resourceName) { 416 try { 417 Context targetContext = getContext().createPackageContext(pkgName, 0); 418 int resId = targetContext.getResources().getIdentifier( 419 pkgName + ":string/" + resourceName, null, null); 420 if (resId != 0) { 421 return targetContext.getResources().getString(resId); 422 } 423 } catch (Resources.NotFoundException | PackageManager.NameNotFoundException 424 | SecurityException e) { 425 Log.w(TAG, "Unable to get string resource " + resourceName, e); 426 } 427 return null; 428 } 429 430 /** 431 * Extracts an drawable resource from a given package. 432 * 433 * @param pkgName the package name 434 * @param resource name, e.g. "my_icon_name" 435 */ getDrawableResource(String pkgName, String resourceName)436 private Drawable getDrawableResource(String pkgName, String resourceName) { 437 try { 438 Context targetContext = getContext().createPackageContext(pkgName, 0); 439 int resId = targetContext.getResources().getIdentifier( 440 pkgName + ":drawable/" + resourceName, null, null); 441 if (resId != 0) { 442 return targetContext.getResources().getDrawable(resId); 443 } 444 } catch (Resources.NotFoundException | PackageManager.NameNotFoundException 445 | SecurityException e) { 446 Log.w(TAG, "Unable to get drawable resource " + resourceName, e); 447 } 448 return null; 449 } 450 451 /** 452 * Returns the ResolveInfo for the system activity that matches given intent filter or null if 453 * no such activity exists. 454 * @param context Context of the caller 455 * @param intent The intent matching the desired system app 456 * @return ResolveInfo of the matching activity or null if no match exists 457 */ systemIntentIsHandled(Context context, Intent intent)458 public static ResolveInfo systemIntentIsHandled(Context context, Intent intent) { 459 if (intent == null) { 460 return null; 461 } 462 463 final PackageManager pm = context.getPackageManager(); 464 465 for (ResolveInfo info : pm.queryIntentActivities(intent, 0)) { 466 if (info.activityInfo != null 467 && (info.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) 468 == ApplicationInfo.FLAG_SYSTEM) { 469 return info; 470 } 471 } 472 return null; 473 } 474 475 @Override onSuggestionReady(List<Suggestion> data)476 public void onSuggestionReady(List<Suggestion> data) { 477 if (data == null || data.size() == 0) { 478 if (mSuggestionsList != null) { 479 getPreferenceScreen().removePreference(mSuggestionsList); 480 mSuggestionsList = null; 481 } 482 return; 483 } 484 485 if (mSuggestionsList == null) { 486 mSuggestionsList = new PreferenceCategory(this.getPreferenceManager().getContext()); 487 mSuggestionsList.setKey(KEY_SUGGESTIONS_LIST); 488 mSuggestionsList.setTitle(R.string.header_category_suggestions); 489 mSuggestionsList.setOrder(0); // always at top 490 getPreferenceScreen().addPreference(mSuggestionsList); 491 } 492 updateSuggestionList(data); 493 } 494 495 @VisibleForTesting updateSuggestionList(List<Suggestion> suggestions)496 void updateSuggestionList(List<Suggestion> suggestions) { 497 // Remove suggestions that are not in the new list. 498 for (int i = 0; i < mSuggestionsList.getPreferenceCount(); i++) { 499 SuggestionPreference pref = (SuggestionPreference) mSuggestionsList.getPreference(i); 500 boolean isInNewSuggestionList = false; 501 for (Suggestion suggestion : suggestions) { 502 if (pref.getId().equals(suggestion.getId())) { 503 isInNewSuggestionList = true; 504 break; 505 } 506 } 507 if (!isInNewSuggestionList) { 508 mSuggestionsList.removePreference(pref); 509 } 510 } 511 512 // Add suggestions that are not in the old list and update the existing suggestions. 513 for (Suggestion suggestion : suggestions) { 514 Preference curPref = findPreference( 515 SuggestionPreference.SUGGESTION_PREFERENCE_KEY + suggestion.getId()); 516 if (curPref == null) { 517 SuggestionPreference newSuggPref = new SuggestionPreference( 518 suggestion, this.getPreferenceManager().getContext(), 519 mSuggestionControllerMixin, this); 520 newSuggPref.setIcon(mIconCache.getIcon(suggestion.getIcon())); 521 newSuggPref.setTitle(suggestion.getTitle()); 522 newSuggPref.setSummary(suggestion.getSummary()); 523 mSuggestionsList.addPreference(newSuggPref); 524 } else { 525 // Even though the id of suggestion might not change, the details could change. 526 // So we need to update icon, title and summary for the suggestions. 527 curPref.setIcon(mIconCache.getIcon(suggestion.getIcon())); 528 curPref.setTitle(suggestion.getTitle()); 529 curPref.setSummary(suggestion.getSummary()); 530 } 531 } 532 } 533 isRestricted()534 private boolean isRestricted() { 535 return SecurityFragment.isRestrictedProfileInEffect(getContext()); 536 } 537 538 @VisibleForTesting updateAccessoryPref()539 void updateAccessoryPref() { 540 SlicePreference connectedDevicesSlicePreference = 541 (SlicePreference) findPreference(KEY_CONNECTED_DEVICES_SLICE); 542 Preference accessoryPreference = findPreference(KEY_ACCESSORIES); 543 Preference connectedDevicesPreference = findPreference(KEY_CONNECTED_DEVICES); 544 if (connectedDevicesSlicePreference != null 545 && FeatureFactory.getFactory(getContext()).isTwoPanelLayout() 546 && SliceUtils.isSliceProviderValid( 547 getContext(), connectedDevicesSlicePreference.getUri())) { 548 connectedDevicesSlicePreference.setVisible(true); 549 connectedDevicesPreference.setVisible(false); 550 accessoryPreference.setVisible(false); 551 return; 552 } 553 554 if (connectedDevicesSlicePreference != null) { 555 connectedDevicesSlicePreference.setVisible(false); 556 } 557 558 if (connectedDevicesPreference != null) { 559 Intent intent = new Intent(ACTION_CONNECTED_DEVICES); 560 ResolveInfo info = systemIntentIsHandled(getContext(), intent); 561 connectedDevicesPreference.setVisible(info != null); 562 connectedDevicesPreference.setOnPreferenceClickListener( 563 preference -> { 564 logEntrySelected(TvSettingsEnums.CONNECTED_CLASSIC); 565 return false; 566 }); 567 accessoryPreference.setVisible(info == null); 568 if (info != null) { 569 String pkgName = info.activityInfo.packageName; 570 Drawable icon = getDrawableResource(pkgName, "connected_devices_pref_icon"); 571 if (icon != null) { 572 connectedDevicesPreference.setIcon(icon); 573 } 574 String title = getStringResource(pkgName, "connected_devices_pref_title"); 575 if (!TextUtils.isEmpty(title)) { 576 connectedDevicesPreference.setTitle(title); 577 } 578 String summary = getStringResource(pkgName, "connected_devices_pref_summary"); 579 if (!TextUtils.isEmpty(summary)) { 580 connectedDevicesPreference.setSummary(summary); 581 } 582 return; 583 } 584 } 585 if (mBtAdapter == null || accessoryPreference == null) { 586 return; 587 } 588 589 final Set<BluetoothDevice> bondedDevices = mBtAdapter.getBondedDevices(); 590 if (bondedDevices.size() == 0) { 591 mHasBtAccessories = false; 592 } else { 593 mHasBtAccessories = true; 594 } 595 } 596 597 @VisibleForTesting updateAccountPref()598 void updateAccountPref() { 599 Preference accountsPref = findPreference(KEY_ACCOUNTS_AND_SIGN_IN); 600 SlicePreference acccountsSlicePref = 601 (SlicePreference) findPreference(KEY_ACCOUNTS_AND_SIGN_IN_SLICE); 602 Intent intent = new Intent(ACTION_ACCOUNTS); 603 604 // If the intent can be handled, use it. 605 if (systemIntentIsHandled(getContext(), intent) != null) { 606 accountsPref.setVisible(true); 607 accountsPref.setFragment(null); 608 accountsPref.setIntent(intent); 609 acccountsSlicePref.setVisible(false); 610 return; 611 } 612 613 // If a slice is available, use it to display the accounts settings, otherwise fall back to 614 // use AccountsFragment. 615 String uri = acccountsSlicePref.getUri(); 616 if (SliceUtils.isSliceProviderValid(getContext(), uri)) { 617 accountsPref.setVisible(false); 618 acccountsSlicePref.setVisible(true); 619 } else { 620 accountsPref.setVisible(true); 621 acccountsSlicePref.setVisible(false); 622 updateAccountPrefInfo(); 623 } 624 } 625 626 @VisibleForTesting updateAccountPrefInfo()627 void updateAccountPrefInfo() { 628 Preference accountsPref = findPreference(KEY_ACCOUNTS_AND_SIGN_IN); 629 if (accountsPref != null && accountsPref.isVisible()) { 630 final AccountManager am = AccountManager.get(getContext()); 631 Account[] accounts = am.getAccounts(); 632 if (accounts.length == 0) { 633 mHasAccounts = false; 634 accountsPref.setIcon(R.drawable.ic_add_an_account); 635 accountsPref.setSummary(R.string.accounts_category_summary_no_account); 636 AccountsFragment.setUpAddAccountPrefIntent(accountsPref, getContext()); 637 } else { 638 mHasAccounts = true; 639 accountsPref.setIcon(R.drawable.ic_accounts_and_sign_in); 640 if (accounts.length == 1) { 641 accountsPref.setSummary(accounts[0].name); 642 } else { 643 accountsPref.setSummary(getResources().getQuantityString( 644 R.plurals.accounts_category_summary, accounts.length, accounts.length)); 645 } 646 } 647 } 648 } 649 650 @Override onStart()651 public void onStart() { 652 super.onStart(); 653 IntentFilter btChangeFilter = new IntentFilter(); 654 btChangeFilter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED); 655 btChangeFilter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED); 656 btChangeFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); 657 getContext().registerReceiver(mBCMReceiver, btChangeFilter); 658 } 659 660 @Override onStop()661 public void onStop() { 662 super.onStop(); 663 getContext().unregisterReceiver(mBCMReceiver); 664 } 665 666 @Override onAttach(Context context)667 public void onAttach(Context context) { 668 super.onAttach(context); 669 ComponentName componentName = new ComponentName( 670 "com.android.settings.intelligence", 671 "com.android.settings.intelligence.suggestions.SuggestionService"); 672 if (!isRestricted()) { 673 mSuggestionControllerMixin = new SuggestionControllerMixin( 674 context, this, getLifecycle(), componentName); 675 } 676 } 677 678 @Override onPreferenceTreeClick(Preference preference)679 public boolean onPreferenceTreeClick(Preference preference) { 680 if (preference.getKey().equals(KEY_ACCOUNTS_AND_SIGN_IN) && !mHasAccounts 681 || (preference.getKey().equals(KEY_ACCESSORIES) && !mHasBtAccessories) 682 || (preference.getKey().equals(KEY_DISPLAY_AND_SOUND) 683 && preference.getIntent() != null) 684 || (preference.getKey().equals(KEY_CHANNELS_AND_INPUTS) 685 && preference.getIntent() != null)) { 686 getContext().startActivity(preference.getIntent()); 687 return true; 688 } else { 689 return super.onPreferenceTreeClick(preference); 690 } 691 } 692 693 @Override onSuggestionClosed(Preference preference)694 public void onSuggestionClosed(Preference preference) { 695 if (mSuggestionsList == null || mSuggestionsList.getPreferenceCount() == 0) { 696 return; 697 } else if (mSuggestionsList.getPreferenceCount() == 1) { 698 getPreferenceScreen().removePreference(mSuggestionsList); 699 } else { 700 mSuggestionsList.removePreference(preference); 701 } 702 } 703 supportBluetooth()704 private boolean supportBluetooth() { 705 return getActivity().getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH) 706 ? true 707 : false; 708 } 709 710 @Override getPageId()711 protected int getPageId() { 712 return TvSettingsEnums.TV_SETTINGS_ROOT; 713 } 714 } 715