• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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