1 /* 2 * Copyright (C) 2022 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.network.tether; 18 19 import static android.net.ConnectivityManager.TETHERING_BLUETOOTH; 20 import static android.net.ConnectivityManager.TETHERING_USB; 21 import static android.net.TetheringManager.TETHERING_ETHERNET; 22 23 import static com.android.settings.wifi.WifiUtils.canShowWifiHotspot; 24 import static com.android.settingslib.RestrictedLockUtilsInternal.checkIfUsbDataSignalingIsDisabled; 25 26 import android.app.Activity; 27 import android.app.settings.SettingsEnums; 28 import android.bluetooth.BluetoothAdapter; 29 import android.bluetooth.BluetoothPan; 30 import android.bluetooth.BluetoothProfile; 31 import android.content.BroadcastReceiver; 32 import android.content.Context; 33 import android.content.Intent; 34 import android.content.IntentFilter; 35 import android.hardware.usb.UsbManager; 36 import android.net.ConnectivityManager; 37 import android.net.EthernetManager; 38 import android.net.IpConfiguration; 39 import android.net.TetheringManager; 40 import android.net.wifi.WifiManager; 41 import android.os.Bundle; 42 import android.os.Environment; 43 import android.os.Handler; 44 import android.os.UserHandle; 45 import android.os.UserManager; 46 import android.provider.SearchIndexableResource; 47 import android.text.TextUtils; 48 import android.util.FeatureFlagUtils; 49 import android.util.Log; 50 51 import androidx.annotation.NonNull; 52 import androidx.annotation.VisibleForTesting; 53 import androidx.lifecycle.ViewModelProvider; 54 import androidx.preference.Preference; 55 import androidx.preference.SwitchPreference; 56 57 import com.android.settings.R; 58 import com.android.settings.RestrictedSettingsFragment; 59 import com.android.settings.Utils; 60 import com.android.settings.core.FeatureFlags; 61 import com.android.settings.datausage.DataSaverBackend; 62 import com.android.settings.search.BaseSearchIndexProvider; 63 import com.android.settings.wifi.tether.WifiTetherPreferenceController; 64 import com.android.settingslib.RestrictedLockUtils; 65 import com.android.settingslib.RestrictedSwitchPreference; 66 import com.android.settingslib.TetherUtil; 67 import com.android.settingslib.search.SearchIndexable; 68 69 import java.lang.ref.WeakReference; 70 import java.util.ArrayList; 71 import java.util.Arrays; 72 import java.util.HashSet; 73 import java.util.List; 74 import java.util.concurrent.atomic.AtomicReference; 75 76 /** 77 * Displays preferences for Tethering. 78 */ 79 @SearchIndexable 80 public class TetherSettings extends RestrictedSettingsFragment 81 implements DataSaverBackend.Listener { 82 83 @VisibleForTesting 84 static final String KEY_TETHER_PREFS_SCREEN = "tether_prefs_screen"; 85 @VisibleForTesting 86 static final String KEY_WIFI_TETHER = "wifi_tether"; 87 @VisibleForTesting 88 static final String KEY_USB_TETHER_SETTINGS = "usb_tether_settings"; 89 @VisibleForTesting 90 static final String KEY_ENABLE_BLUETOOTH_TETHERING = "enable_bluetooth_tethering"; 91 private static final String KEY_ENABLE_ETHERNET_TETHERING = "enable_ethernet_tethering"; 92 private static final String KEY_DATA_SAVER_FOOTER = "disabled_on_data_saver"; 93 @VisibleForTesting 94 static final String KEY_TETHER_PREFS_TOP_INTRO = "tether_prefs_top_intro"; 95 96 private static final String TAG = "TetheringSettings"; 97 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 98 99 @VisibleForTesting 100 RestrictedSwitchPreference mUsbTether; 101 @VisibleForTesting 102 SwitchPreference mBluetoothTether; 103 @VisibleForTesting 104 SwitchPreference mEthernetTether; 105 106 private BroadcastReceiver mTetherChangeReceiver; 107 private BroadcastReceiver mBluetoothStateReceiver; 108 109 private String[] mBluetoothRegexs; 110 private AtomicReference<BluetoothPan> mBluetoothPan = new AtomicReference<>(); 111 112 private Handler mHandler = new Handler(); 113 private OnStartTetheringCallback mStartTetheringCallback; 114 private ConnectivityManager mCm; 115 private EthernetManager mEm; 116 private EthernetListener mEthernetListener; 117 private final HashSet<String> mAvailableInterfaces = new HashSet<>(); 118 119 @VisibleForTesting 120 WifiTetherPreferenceController mWifiTetherPreferenceController; 121 122 private boolean mUsbConnected; 123 private boolean mMassStorageActive; 124 125 private boolean mBluetoothEnableForTether; 126 127 private DataSaverBackend mDataSaverBackend; 128 private boolean mDataSaverEnabled; 129 @VisibleForTesting 130 Preference mDataSaverFooter; 131 132 @VisibleForTesting 133 String[] mUsbRegexs; 134 @VisibleForTesting 135 Context mContext; 136 @VisibleForTesting 137 TetheringManager mTm; 138 139 @Override getMetricsCategory()140 public int getMetricsCategory() { 141 return SettingsEnums.TETHER; 142 } 143 TetherSettings()144 public TetherSettings() { 145 super(UserManager.DISALLOW_CONFIG_TETHERING); 146 } 147 148 @Override onCreate(Bundle icicle)149 public void onCreate(Bundle icicle) { 150 super.onCreate(icicle); 151 // Even when the UI is restricted, addPreferencesFromResource cannot be omitted. 152 addPreferencesFromResource(R.xml.tether_prefs); 153 setIfOnlyAvailableForAdmins(true); 154 if (isUiRestricted()) { 155 return; 156 } 157 158 mContext = getContext(); 159 mDataSaverBackend = new DataSaverBackend(mContext); 160 mDataSaverEnabled = mDataSaverBackend.isDataSaverEnabled(); 161 mDataSaverFooter = findPreference(KEY_DATA_SAVER_FOOTER); 162 163 setupTetherPreference(); 164 setupViewModel(); 165 166 final Activity activity = getActivity(); 167 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 168 if (adapter != null) { 169 adapter.getProfileProxy(activity.getApplicationContext(), mProfileServiceListener, 170 BluetoothProfile.PAN); 171 } 172 if (mBluetoothStateReceiver == null) { 173 mBluetoothStateReceiver = new BluetoothStateReceiver(); 174 mContext.registerReceiver( 175 mBluetoothStateReceiver, 176 new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED)); 177 } 178 179 setTopIntroPreferenceTitle(); 180 181 mDataSaverBackend.addListener(this); 182 183 mCm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); 184 // Some devices do not have available EthernetManager. In that case getSystemService will 185 // return null. 186 mEm = mContext.getSystemService(EthernetManager.class); 187 188 mUsbRegexs = mTm.getTetherableUsbRegexs(); 189 mBluetoothRegexs = mTm.getTetherableBluetoothRegexs(); 190 191 final boolean usbAvailable = mUsbRegexs.length != 0; 192 final boolean bluetoothAvailable = adapter != null && mBluetoothRegexs.length != 0; 193 final boolean ethernetAvailable = (mEm != null); 194 195 if (!usbAvailable || Utils.isMonkeyRunning()) { 196 getPreferenceScreen().removePreference(mUsbTether); 197 } 198 199 mWifiTetherPreferenceController.displayPreference(getPreferenceScreen()); 200 201 if (!bluetoothAvailable) { 202 getPreferenceScreen().removePreference(mBluetoothTether); 203 } else { 204 BluetoothPan pan = mBluetoothPan.get(); 205 if (pan != null && pan.isTetheringOn()) { 206 mBluetoothTether.setChecked(true); 207 } else { 208 mBluetoothTether.setChecked(false); 209 } 210 } 211 if (!ethernetAvailable) getPreferenceScreen().removePreference(mEthernetTether); 212 // Set initial state based on Data Saver mode. 213 onDataSaverChanged(mDataSaverBackend.isDataSaverEnabled()); 214 } 215 216 @VisibleForTesting setupViewModel()217 void setupViewModel() { 218 TetheringManagerModel model = new ViewModelProvider(this).get(TetheringManagerModel.class); 219 mWifiTetherPreferenceController = 220 new WifiTetherPreferenceController(getContext(), getSettingsLifecycle(), model); 221 mTm = model.getTetheringManager(); 222 model.getTetheredInterfaces().observe(this, this::onTetheredInterfacesChanged); 223 } 224 225 @Override onDestroy()226 public void onDestroy() { 227 if (isUiRestricted()) { 228 super.onDestroy(); 229 return; 230 } 231 232 mDataSaverBackend.remListener(this); 233 234 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 235 BluetoothProfile profile = mBluetoothPan.getAndSet(null); 236 if (profile != null && adapter != null) { 237 adapter.closeProfileProxy(BluetoothProfile.PAN, profile); 238 } 239 if (mBluetoothStateReceiver != null) { 240 mContext.unregisterReceiver(mBluetoothStateReceiver); 241 mBluetoothStateReceiver = null; 242 } 243 244 super.onDestroy(); 245 } 246 247 @VisibleForTesting setupTetherPreference()248 void setupTetherPreference() { 249 mUsbTether = (RestrictedSwitchPreference) findPreference(KEY_USB_TETHER_SETTINGS); 250 mBluetoothTether = (SwitchPreference) findPreference(KEY_ENABLE_BLUETOOTH_TETHERING); 251 mEthernetTether = (SwitchPreference) findPreference(KEY_ENABLE_ETHERNET_TETHERING); 252 } 253 254 @Override onDataSaverChanged(boolean isDataSaving)255 public void onDataSaverChanged(boolean isDataSaving) { 256 mDataSaverEnabled = isDataSaving; 257 mWifiTetherPreferenceController.setDataSaverEnabled(mDataSaverEnabled); 258 mUsbTether.setEnabled(!mDataSaverEnabled); 259 mBluetoothTether.setEnabled(!mDataSaverEnabled); 260 mEthernetTether.setEnabled(!mDataSaverEnabled); 261 mDataSaverFooter.setVisible(mDataSaverEnabled); 262 } 263 264 @Override onAllowlistStatusChanged(int uid, boolean isAllowlisted)265 public void onAllowlistStatusChanged(int uid, boolean isAllowlisted) { 266 } 267 268 @Override onDenylistStatusChanged(int uid, boolean isDenylisted)269 public void onDenylistStatusChanged(int uid, boolean isDenylisted) { 270 } 271 272 @VisibleForTesting setTopIntroPreferenceTitle()273 void setTopIntroPreferenceTitle() { 274 final Preference topIntroPreference = findPreference(KEY_TETHER_PREFS_TOP_INTRO); 275 final WifiManager wifiManager = mContext.getSystemService(WifiManager.class); 276 if (wifiManager.isStaApConcurrencySupported()) { 277 topIntroPreference.setTitle(R.string.tethering_footer_info_sta_ap_concurrency); 278 } else { 279 topIntroPreference.setTitle(R.string.tethering_footer_info); 280 } 281 } 282 283 private class BluetoothStateReceiver extends BroadcastReceiver { 284 @Override onReceive(Context context, Intent intent)285 public void onReceive(Context context, Intent intent) { 286 final String action = intent.getAction(); 287 Log.i(TAG, "onReceive: action: " + action); 288 289 if (TextUtils.equals(action, BluetoothAdapter.ACTION_STATE_CHANGED)) { 290 final int state = 291 intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR); 292 Log.i(TAG, "onReceive: state: " + BluetoothAdapter.nameForState(state)); 293 final BluetoothProfile profile = mBluetoothPan.get(); 294 switch(state) { 295 case BluetoothAdapter.STATE_ON: 296 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 297 if (profile == null && adapter != null) { 298 adapter.getProfileProxy(mContext, mProfileServiceListener, 299 BluetoothProfile.PAN); 300 } 301 break; 302 } 303 } 304 } 305 } 306 307 private class TetherChangeReceiver extends BroadcastReceiver { 308 @Override onReceive(Context content, Intent intent)309 public void onReceive(Context content, Intent intent) { 310 String action = intent.getAction(); 311 if (DEBUG) { 312 Log.d(TAG, "onReceive() action : " + action); 313 } 314 // TODO(b/194961339): Stop using ACTION_TETHER_STATE_CHANGED and use 315 // mTetheringEventCallback instead. 316 if (action.equals(TetheringManager.ACTION_TETHER_STATE_CHANGED)) { 317 // TODO - this should understand the interface types 318 ArrayList<String> available = intent.getStringArrayListExtra( 319 TetheringManager.EXTRA_AVAILABLE_TETHER); 320 ArrayList<String> active = intent.getStringArrayListExtra( 321 TetheringManager.EXTRA_ACTIVE_TETHER); 322 updateBluetoothState(); 323 updateEthernetState(available.toArray(new String[available.size()]), 324 active.toArray(new String[active.size()])); 325 } else if (action.equals(Intent.ACTION_MEDIA_SHARED)) { 326 mMassStorageActive = true; 327 updateBluetoothAndEthernetState(); 328 updateUsbPreference(); 329 } else if (action.equals(Intent.ACTION_MEDIA_UNSHARED)) { 330 mMassStorageActive = false; 331 updateBluetoothAndEthernetState(); 332 updateUsbPreference(); 333 } else if (action.equals(UsbManager.ACTION_USB_STATE)) { 334 mUsbConnected = intent.getBooleanExtra(UsbManager.USB_CONNECTED, false); 335 updateBluetoothAndEthernetState(); 336 updateUsbPreference(); 337 } else if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) { 338 if (mBluetoothEnableForTether) { 339 switch (intent 340 .getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR)) { 341 case BluetoothAdapter.STATE_ON: 342 startTethering(TETHERING_BLUETOOTH); 343 mBluetoothEnableForTether = false; 344 break; 345 346 case BluetoothAdapter.STATE_OFF: 347 case BluetoothAdapter.ERROR: 348 mBluetoothEnableForTether = false; 349 break; 350 351 default: 352 // ignore transition states 353 } 354 } 355 updateBluetoothAndEthernetState(); 356 } else if (action.equals(BluetoothPan.ACTION_TETHERING_STATE_CHANGED)) { 357 updateBluetoothAndEthernetState(); 358 } 359 } 360 } 361 362 @Override onStart()363 public void onStart() { 364 super.onStart(); 365 366 if (isUiRestricted()) { 367 if (!isUiRestrictedByOnlyAdmin()) { 368 getEmptyTextView().setText(R.string.tethering_settings_not_available); 369 } 370 getPreferenceScreen().removeAll(); 371 return; 372 } 373 374 375 mStartTetheringCallback = new OnStartTetheringCallback(this); 376 377 mMassStorageActive = Environment.MEDIA_SHARED.equals(Environment.getExternalStorageState()); 378 registerReceiver(); 379 380 mEthernetListener = new EthernetListener(this); 381 if (mEm != null) { 382 mEm.addInterfaceStateListener(mContext.getApplicationContext().getMainExecutor(), 383 mEthernetListener); 384 } 385 386 updateUsbState(); 387 updateBluetoothAndEthernetState(); 388 } 389 390 @Override onStop()391 public void onStop() { 392 super.onStop(); 393 394 if (isUiRestricted()) { 395 return; 396 } 397 getActivity().unregisterReceiver(mTetherChangeReceiver); 398 if (mEm != null) { 399 mEm.removeInterfaceStateListener(mEthernetListener); 400 } 401 mTetherChangeReceiver = null; 402 mStartTetheringCallback = null; 403 } 404 405 @VisibleForTesting registerReceiver()406 void registerReceiver() { 407 final Activity activity = getActivity(); 408 409 mTetherChangeReceiver = new TetherChangeReceiver(); 410 IntentFilter filter = new IntentFilter(TetheringManager.ACTION_TETHER_STATE_CHANGED); 411 final Intent intent = activity.registerReceiver(mTetherChangeReceiver, filter); 412 413 filter = new IntentFilter(); 414 filter.addAction(UsbManager.ACTION_USB_STATE); 415 activity.registerReceiver(mTetherChangeReceiver, filter); 416 417 filter = new IntentFilter(); 418 filter.addAction(Intent.ACTION_MEDIA_SHARED); 419 filter.addAction(Intent.ACTION_MEDIA_UNSHARED); 420 filter.addDataScheme("file"); 421 activity.registerReceiver(mTetherChangeReceiver, filter); 422 423 filter = new IntentFilter(); 424 filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); 425 filter.addAction(BluetoothPan.ACTION_TETHERING_STATE_CHANGED); 426 activity.registerReceiver(mTetherChangeReceiver, filter); 427 428 if (intent != null) mTetherChangeReceiver.onReceive(activity, intent); 429 } 430 431 // TODO(b/194961339): Separate the updateBluetoothAndEthernetState() to two methods, 432 // updateBluetoothAndEthernetState() and updateBluetoothAndEthernetPreference(). 433 // Because we should update the state when only receiving tethering 434 // state changes and update preference when usb or media share changed. updateBluetoothAndEthernetState()435 private void updateBluetoothAndEthernetState() { 436 String[] tethered = mTm.getTetheredIfaces(); 437 updateBluetoothAndEthernetState(tethered); 438 } 439 updateBluetoothAndEthernetState(String[] tethered)440 private void updateBluetoothAndEthernetState(String[] tethered) { 441 String[] available = mTm.getTetherableIfaces(); 442 updateBluetoothState(); 443 updateEthernetState(available, tethered); 444 } 445 updateUsbState()446 private void updateUsbState() { 447 String[] tethered = mTm.getTetheredIfaces(); 448 updateUsbState(tethered); 449 } 450 451 @VisibleForTesting updateUsbState(String[] tethered)452 void updateUsbState(String[] tethered) { 453 boolean usbTethered = false; 454 for (String s : tethered) { 455 for (String regex : mUsbRegexs) { 456 if (s.matches(regex)) usbTethered = true; 457 } 458 } 459 if (DEBUG) { 460 Log.d(TAG, "updateUsbState() mUsbConnected : " + mUsbConnected 461 + ", mMassStorageActive : " + mMassStorageActive 462 + ", usbTethered : " + usbTethered); 463 } 464 if (usbTethered) { 465 mUsbTether.setEnabled(!mDataSaverEnabled); 466 mUsbTether.setChecked(true); 467 final RestrictedLockUtils.EnforcedAdmin enforcedAdmin = 468 checkIfUsbDataSignalingIsDisabled(mContext, UserHandle.myUserId()); 469 if (enforcedAdmin != null) { 470 mUsbTether.setDisabledByAdmin(enforcedAdmin); 471 } 472 } else { 473 mUsbTether.setChecked(false); 474 updateUsbPreference(); 475 } 476 } 477 updateUsbPreference()478 private void updateUsbPreference() { 479 boolean usbAvailable = mUsbConnected && !mMassStorageActive; 480 final RestrictedLockUtils.EnforcedAdmin enforcedAdmin = 481 checkIfUsbDataSignalingIsDisabled(mContext, UserHandle.myUserId()); 482 483 if (enforcedAdmin != null) { 484 mUsbTether.setDisabledByAdmin(enforcedAdmin); 485 } else if (usbAvailable) { 486 mUsbTether.setEnabled(!mDataSaverEnabled); 487 } else { 488 mUsbTether.setEnabled(false); 489 } 490 } 491 492 @VisibleForTesting getBluetoothState()493 int getBluetoothState() { 494 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 495 if (adapter == null) { 496 return BluetoothAdapter.ERROR; 497 } 498 return adapter.getState(); 499 } 500 501 @VisibleForTesting isBluetoothTetheringOn()502 boolean isBluetoothTetheringOn() { 503 final BluetoothPan bluetoothPan = mBluetoothPan.get(); 504 return bluetoothPan != null && bluetoothPan.isTetheringOn(); 505 } 506 updateBluetoothState()507 private void updateBluetoothState() { 508 final int btState = getBluetoothState(); 509 if (DEBUG) { 510 Log.d(TAG, "updateBluetoothState() btState : " + btState); 511 } 512 if (btState == BluetoothAdapter.ERROR) { 513 Log.w(TAG, "updateBluetoothState() Bluetooth state is error!"); 514 return; 515 } 516 517 if (btState == BluetoothAdapter.STATE_TURNING_OFF) { 518 mBluetoothTether.setEnabled(false); 519 } else if (btState == BluetoothAdapter.STATE_TURNING_ON) { 520 mBluetoothTether.setEnabled(false); 521 } else { 522 if (btState == BluetoothAdapter.STATE_ON && isBluetoothTetheringOn()) { 523 mBluetoothTether.setChecked(true); 524 mBluetoothTether.setEnabled(!mDataSaverEnabled); 525 } else { 526 mBluetoothTether.setEnabled(!mDataSaverEnabled); 527 mBluetoothTether.setChecked(false); 528 } 529 } 530 } 531 532 @VisibleForTesting updateEthernetState(String[] available, String[] tethered)533 void updateEthernetState(String[] available, String[] tethered) { 534 boolean isAvailable = false; 535 boolean isTethered = false; 536 537 for (String s : available) { 538 if (mAvailableInterfaces.contains(s)) isAvailable = true; 539 } 540 541 for (String s : tethered) { 542 if (mAvailableInterfaces.contains(s)) isTethered = true; 543 } 544 545 if (DEBUG) { 546 Log.d(TAG, "updateEthernetState() isAvailable : " + isAvailable 547 + ", isTethered : " + isTethered); 548 } 549 550 if (isTethered) { 551 mEthernetTether.setEnabled(!mDataSaverEnabled); 552 mEthernetTether.setChecked(true); 553 } else if (mAvailableInterfaces.size() > 0) { 554 mEthernetTether.setEnabled(!mDataSaverEnabled); 555 mEthernetTether.setChecked(false); 556 } else { 557 mEthernetTether.setEnabled(false); 558 mEthernetTether.setChecked(false); 559 } 560 } 561 startTethering(int choice)562 private void startTethering(int choice) { 563 if (choice == TETHERING_BLUETOOTH) { 564 // Turn on Bluetooth first. 565 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 566 if (adapter.getState() == BluetoothAdapter.STATE_OFF) { 567 mBluetoothEnableForTether = true; 568 adapter.enable(); 569 mBluetoothTether.setEnabled(false); 570 return; 571 } 572 } 573 574 mCm.startTethering(choice, true, mStartTetheringCallback, mHandler); 575 } 576 577 @Override onPreferenceTreeClick(Preference preference)578 public boolean onPreferenceTreeClick(Preference preference) { 579 if (preference == mUsbTether) { 580 if (mUsbTether.isChecked()) { 581 startTethering(TETHERING_USB); 582 } else { 583 mCm.stopTethering(TETHERING_USB); 584 } 585 } else if (preference == mBluetoothTether) { 586 if (mBluetoothTether.isChecked()) { 587 startTethering(TETHERING_BLUETOOTH); 588 } else { 589 mCm.stopTethering(TETHERING_BLUETOOTH); 590 } 591 } else if (preference == mEthernetTether) { 592 if (mEthernetTether.isChecked()) { 593 startTethering(TETHERING_ETHERNET); 594 } else { 595 mCm.stopTethering(TETHERING_ETHERNET); 596 } 597 } 598 599 return super.onPreferenceTreeClick(preference); 600 } 601 602 @Override getHelpResource()603 public int getHelpResource() { 604 return R.string.help_url_tether; 605 } 606 607 private BluetoothProfile.ServiceListener mProfileServiceListener = 608 new BluetoothProfile.ServiceListener() { 609 @Override 610 public void onServiceConnected(int profile, BluetoothProfile proxy) { 611 if (mBluetoothPan.get() == null) { 612 mBluetoothPan.set((BluetoothPan) proxy); 613 updateBluetoothState(); 614 } 615 } 616 617 @Override 618 public void onServiceDisconnected(int profile) { /* Do nothing */ } 619 }; 620 621 public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = 622 new BaseSearchIndexProvider() { 623 @Override 624 public List<SearchIndexableResource> getXmlResourcesToIndex( 625 Context context, boolean enabled) { 626 final SearchIndexableResource sir = new SearchIndexableResource(context); 627 sir.xmlResId = R.xml.tether_prefs; 628 return Arrays.asList(sir); 629 } 630 631 @Override 632 protected boolean isPageSearchEnabled(Context context) { 633 return !FeatureFlagUtils.isEnabled(context, FeatureFlags.TETHER_ALL_IN_ONE); 634 } 635 636 @Override 637 public List<String> getNonIndexableKeys(Context context) { 638 final List<String> keys = super.getNonIndexableKeys(context); 639 final TetheringManager tm = 640 context.getSystemService(TetheringManager.class); 641 642 if (!TetherUtil.isTetherAvailable(context)) { 643 keys.add(KEY_TETHER_PREFS_SCREEN); 644 } 645 646 if (!canShowWifiHotspot(context) || !TetherUtil.isTetherAvailable(context)) { 647 keys.add(KEY_WIFI_TETHER); 648 } 649 650 final boolean usbAvailable = 651 tm.getTetherableUsbRegexs().length != 0; 652 if (!usbAvailable || Utils.isMonkeyRunning()) { 653 keys.add(KEY_USB_TETHER_SETTINGS); 654 } 655 656 final boolean bluetoothAvailable = 657 tm.getTetherableBluetoothRegexs().length != 0; 658 if (!bluetoothAvailable) { 659 keys.add(KEY_ENABLE_BLUETOOTH_TETHERING); 660 } 661 662 final EthernetManager em = 663 context.getSystemService(EthernetManager.class); 664 final boolean ethernetAvailable = (em != null); 665 if (!ethernetAvailable) { 666 keys.add(KEY_ENABLE_ETHERNET_TETHERING); 667 } 668 return keys; 669 } 670 }; 671 672 private static final class OnStartTetheringCallback extends 673 ConnectivityManager.OnStartTetheringCallback { 674 final WeakReference<TetherSettings> mTetherSettings; 675 OnStartTetheringCallback(TetherSettings settings)676 OnStartTetheringCallback(TetherSettings settings) { 677 mTetherSettings = new WeakReference<>(settings); 678 } 679 680 @Override onTetheringStarted()681 public void onTetheringStarted() { 682 update(); 683 } 684 685 @Override onTetheringFailed()686 public void onTetheringFailed() { 687 update(); 688 } 689 update()690 private void update() { 691 TetherSettings settings = mTetherSettings.get(); 692 if (settings != null) { 693 settings.updateBluetoothAndEthernetState(); 694 } 695 } 696 } 697 onTetheredInterfacesChanged(List<String> interfaces)698 protected void onTetheredInterfacesChanged(List<String> interfaces) { 699 Log.d(TAG, "onTetheredInterfacesChanged() interfaces : " + interfaces.toString()); 700 final String[] tethered = interfaces.toArray(new String[interfaces.size()]); 701 updateUsbState(tethered); 702 updateBluetoothAndEthernetState(tethered); 703 } 704 705 private static final class EthernetListener implements EthernetManager.InterfaceStateListener { 706 final WeakReference<TetherSettings> mTetherSettings; 707 EthernetListener(TetherSettings settings)708 EthernetListener(TetherSettings settings) { 709 mTetherSettings = new WeakReference<>(settings); 710 } 711 712 @Override onInterfaceStateChanged(@onNull String iface, int state, int role, @NonNull IpConfiguration configuration)713 public void onInterfaceStateChanged(@NonNull String iface, int state, int role, 714 @NonNull IpConfiguration configuration) { 715 final TetherSettings tetherSettings = mTetherSettings.get(); 716 if (tetherSettings == null) { 717 return; 718 } 719 tetherSettings.onInterfaceStateChanged(iface, state, role, configuration); 720 } 721 } 722 onInterfaceStateChanged(@onNull String iface, int state, int role, @NonNull IpConfiguration configuration)723 void onInterfaceStateChanged(@NonNull String iface, int state, int role, 724 @NonNull IpConfiguration configuration) { 725 if (state == EthernetManager.STATE_LINK_UP) { 726 mAvailableInterfaces.add(iface); 727 } else { 728 mAvailableInterfaces.remove(iface); 729 } 730 updateBluetoothAndEthernetState(); 731 } 732 } 733