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