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