From 7f2d6ce0586dc33f075b1d5733b3715eb3dd4f0c Mon Sep 17 00:00:00 2001 From: Zhen Zhang Date: Sun, 15 Mar 2020 11:18:01 -0700 Subject: [PATCH 1/2] Refactor new tether settings to remove SharedPreferences Bluetooth, USB and Wifi Disable tether preferences will turn on/off that type of tethering interface instantly without storing it into SharedPreferences. They are listening to TetherEnabler to update their state. Refactored to remove dependancy on SharedPreferences. Bug: 151367756 Test: TetherEnablerTest; BluetoothTetherPreferenceControllerTest; UsbTetherPreferenceControllerTest; WifiTetherDisablePreferenceControllerTest; AllInOneSettingsTest; AllInOneTetherPreferenceControllerTest Change-Id: Ia6cc60bc4de8f08413beb6d41552a18f6fa6a55b --- .../settings/AllInOneTetherSettings.java | 43 ++-- .../AllInOneTetherPreferenceController.java | 63 +++-- .../BluetoothTetherPreferenceController.java | 64 ++--- .../TetherBasePreferenceController.java | 74 ++++++ .../settings/network/TetherEnabler.java | 230 +++++++----------- .../UsbTetherPreferenceController.java | 64 ++--- ...WifiTetherDisablePreferenceController.java | 106 ++------ ...llInOneTetherPreferenceControllerTest.java | 5 - ...uetoothTetherPreferenceControllerTest.java | 45 +++- .../settings/network/TetherEnablerTest.java | 115 +++++---- .../UsbTetherPreferenceControllerTest.java | 45 +++- ...TetherDisablePreferenceControllerTest.java | 50 +--- 12 files changed, 406 insertions(+), 498 deletions(-) create mode 100644 src/com/android/settings/network/TetherBasePreferenceController.java diff --git a/src/com/android/settings/AllInOneTetherSettings.java b/src/com/android/settings/AllInOneTetherSettings.java index 251d1357b25..69edf4348b6 100644 --- a/src/com/android/settings/AllInOneTetherSettings.java +++ b/src/com/android/settings/AllInOneTetherSettings.java @@ -20,8 +20,6 @@ import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED; import static android.net.ConnectivityManager.TETHERING_WIFI; import static android.net.wifi.WifiManager.WIFI_AP_STATE_CHANGED_ACTION; -import static com.android.settings.network.TetherEnabler.KEY_ENABLE_WIFI_TETHERING; - import android.app.settings.SettingsEnums; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothPan; @@ -30,7 +28,6 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.SharedPreferences; import android.net.wifi.SoftApConfiguration; import android.net.wifi.WifiManager; import android.os.Bundle; @@ -74,8 +71,7 @@ import java.util.concurrent.atomic.AtomicReference; @SearchIndexable public class AllInOneTetherSettings extends RestrictedDashboardFragment implements DataSaverBackend.Listener, - WifiTetherBasePreferenceController.OnTetherConfigUpdateListener, - SharedPreferences.OnSharedPreferenceChangeListener { + WifiTetherBasePreferenceController.OnTetherConfigUpdateListener { // TODO(b/148622133): Should clean up the postfix once this fragment replaced TetherSettings. public static final String DEDUP_POSTFIX = "_2"; @@ -114,9 +110,18 @@ public class AllInOneTetherSettings extends RestrictedDashboardFragment private WifiTetherApBandPreferenceController mApBandPreferenceController; private WifiTetherSecurityPreferenceController mSecurityPreferenceController; private PreferenceGroup mWifiTetherGroup; - private SharedPreferences mSharedPreferences; - private boolean mWifiTetherChosen; + private boolean mBluetoothTethering; + private boolean mUsbTethering; + private boolean mWifiTethering; private TetherEnabler mTetherEnabler; + private final TetherEnabler.OnTetherStateUpdateListener mStateUpdateListener = + state -> { + mBluetoothTethering = TetherEnabler.isBluetoothTethering(state); + mUsbTethering = TetherEnabler.isUsbTethering(state); + mWifiTethering = TetherEnabler.isWifiTethering(state); + mWifiTetherGroup.setVisible(shouldShowWifiConfig()); + reConfigInitialExpandedChildCount(); + }; private final BroadcastReceiver mTetherChangeReceiver = new BroadcastReceiver() { @Override @@ -136,7 +141,6 @@ public class AllInOneTetherSettings extends RestrictedDashboardFragment private void restartWifiTetherIfNeed(int state) { if (state == WifiManager.WIFI_AP_STATE_DISABLED - && mWifiTetherChosen && mRestartWifiApAfterConfigChange) { mRestartWifiApAfterConfigChange = false; mTetherEnabler.startTethering(TETHERING_WIFI); @@ -168,8 +172,6 @@ public class AllInOneTetherSettings extends RestrictedDashboardFragment public void onAttach(Context context) { super.onAttach(context); mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); - mSharedPreferences = - context.getSharedPreferences(TetherEnabler.SHARED_PREF, Context.MODE_PRIVATE); mSSIDPreferenceController = use(WifiTetherSSIDPreferenceController.class); mSecurityPreferenceController = use(WifiTetherSecurityPreferenceController.class); @@ -199,9 +201,6 @@ public class AllInOneTetherSettings extends RestrictedDashboardFragment // Set initial state based on Data Saver mode. onDataSaverChanged(mDataSaverBackend.isDataSaverEnabled()); - - // Set initial state based on SharedPreferences value. - onSharedPreferenceChanged(mSharedPreferences, KEY_ENABLE_WIFI_TETHERING); } @Override @@ -222,6 +221,9 @@ public class AllInOneTetherSettings extends RestrictedDashboardFragment mTetherEnabler = new TetherEnabler(activity, new SwitchBarController(switchBar), mBluetoothPan); getSettingsLifecycle().addObserver(mTetherEnabler); + use(UsbTetherPreferenceController.class).setTetherEnabler(mTetherEnabler); + use(BluetoothTetherPreferenceController.class).setTetherEnabler(mTetherEnabler); + use(WifiTetherDisablePreferenceController.class).setTetherEnabler(mTetherEnabler); switchBar.show(); } @@ -247,13 +249,13 @@ public class AllInOneTetherSettings extends RestrictedDashboardFragment @Override public void onResume() { super.onResume(); - mSharedPreferences.registerOnSharedPreferenceChangeListener(this); + mTetherEnabler.addListener(mStateUpdateListener); } @Override public void onPause() { super.onPause(); - mSharedPreferences.unregisterOnSharedPreferenceChangeListener(this); + mTetherEnabler.removeListener(mStateUpdateListener); } @Override @@ -365,13 +367,8 @@ public class AllInOneTetherSettings extends RestrictedDashboardFragment mApBandPreferenceController.updateDisplay(); } - @Override - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { - if (TextUtils.equals(key, KEY_ENABLE_WIFI_TETHERING)) { - mWifiTetherChosen = sharedPreferences.getBoolean(KEY_ENABLE_WIFI_TETHERING, true); - mWifiTetherGroup.setVisible(mWifiTetherChosen); - reConfigInitialExpandedChildCount(); - } + private boolean shouldShowWifiConfig() { + return mWifiTethering || (!mBluetoothTethering && !mUsbTethering); } private void reConfigInitialExpandedChildCount() { @@ -380,7 +377,7 @@ public class AllInOneTetherSettings extends RestrictedDashboardFragment @Override public int getInitialExpandedChildCount() { - if (!mWifiTetherChosen) { + if (!shouldShowWifiConfig()) { // Expand all preferences in the screen. return getPreferenceScreen().getPreferenceCount(); } diff --git a/src/com/android/settings/network/AllInOneTetherPreferenceController.java b/src/com/android/settings/network/AllInOneTetherPreferenceController.java index 85cfb8bc931..50c3a6439ed 100644 --- a/src/com/android/settings/network/AllInOneTetherPreferenceController.java +++ b/src/com/android/settings/network/AllInOneTetherPreferenceController.java @@ -17,16 +17,12 @@ package com.android.settings.network; import static android.os.UserManager.DISALLOW_CONFIG_TETHERING; -import static com.android.settings.network.TetherEnabler.BLUETOOTH_TETHER_KEY; -import static com.android.settings.network.TetherEnabler.KEY_ENABLE_WIFI_TETHERING; -import static com.android.settings.network.TetherEnabler.USB_TETHER_KEY; import static com.android.settingslib.RestrictedLockUtilsInternal.checkIfRestrictionEnforced; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothPan; import android.bluetooth.BluetoothProfile; import android.content.Context; -import android.content.SharedPreferences; import android.os.UserHandle; import android.util.FeatureFlagUtils; import android.util.Log; @@ -56,19 +52,23 @@ public class AllInOneTetherPreferenceController extends BasePreferenceController LifecycleObserver, TetherEnabler.OnTetherStateUpdateListener { private static final String TAG = "AllInOneTetherPreferenceController"; - private static final byte HOTSPOT_ONLY = 1; - private static final byte USB_ONLY = 1 << 1; - private static final byte BLUETOOTH_ONLY = 1 << 2; - private static final byte HOTSPOT_AND_USB = HOTSPOT_ONLY | USB_ONLY; - private static final byte HOTSPOT_AND_BLUETOOTH = HOTSPOT_ONLY | BLUETOOTH_ONLY; - private static final byte USB_AND_BLUETOOTH = USB_ONLY | BLUETOOTH_ONLY; - private static final byte HOTSPOT_AND_USB_AND_BLUETOOTH = - HOTSPOT_ONLY | USB_ONLY | BLUETOOTH_ONLY; + private static final byte TETHERING_TYPE_HOTSPOT_ONLY = 1; + private static final byte TETHERING_TYPE_USB_ONLY = 1 << 1; + private static final byte TETHERING_TYPE_BLUETOOTH_ONLY = 1 << 2; + private static final byte TETHERING_TYPE_HOTSPOT_AND_USB = + TETHERING_TYPE_HOTSPOT_ONLY | TETHERING_TYPE_USB_ONLY; + private static final byte TETHERING_TYPE_HOTSPOT_AND_BLUETOOTH = + TETHERING_TYPE_HOTSPOT_ONLY | TETHERING_TYPE_BLUETOOTH_ONLY; + private static final byte TETHERING_TYPE_USB_AND_BLUETOOTH = + TETHERING_TYPE_USB_ONLY | TETHERING_TYPE_BLUETOOTH_ONLY; + private static final byte TETHERING_TYPE_HOTSPOT_AND_USB_AND_BLUETOOTH = + TETHERING_TYPE_HOTSPOT_ONLY | TETHERING_TYPE_USB_ONLY | TETHERING_TYPE_BLUETOOTH_ONLY; + // A bitwise value that stands for the current tethering interface type. + private int mTetheringType; private final boolean mAdminDisallowedTetherConfig; private final AtomicReference mBluetoothPan; private final BluetoothAdapter mBluetoothAdapter; - private final SharedPreferences mTetherEnablerSharedPreferences; @VisibleForTesting final BluetoothProfile.ServiceListener mBtProfileServiceListener = new BluetoothProfile.ServiceListener() { @@ -92,7 +92,6 @@ public class AllInOneTetherPreferenceController extends BasePreferenceController mAdminDisallowedTetherConfig = false; mBluetoothPan = new AtomicReference<>(); mBluetoothAdapter = null; - mTetherEnablerSharedPreferences = null; } public AllInOneTetherPreferenceController(Context context, String key) { @@ -101,8 +100,6 @@ public class AllInOneTetherPreferenceController extends BasePreferenceController mAdminDisallowedTetherConfig = checkIfRestrictionEnforced( context, DISALLOW_CONFIG_TETHERING, UserHandle.myUserId()) != null; mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); - mTetherEnablerSharedPreferences = - context.getSharedPreferences(TetherEnabler.SHARED_PREF, Context.MODE_PRIVATE); } @Override @@ -128,29 +125,22 @@ public class AllInOneTetherPreferenceController extends BasePreferenceController @Override public CharSequence getSummary() { if (mPreference != null && mPreference.isChecked()) { - int chosenType = 0; - chosenType |= mTetherEnablerSharedPreferences - .getBoolean(KEY_ENABLE_WIFI_TETHERING, true) ? HOTSPOT_ONLY : 0; - chosenType |= mTetherEnablerSharedPreferences.getBoolean(USB_TETHER_KEY, false) - ? USB_ONLY : 0; - chosenType |= mTetherEnablerSharedPreferences.getBoolean(BLUETOOTH_TETHER_KEY, false) - ? BLUETOOTH_ONLY : 0; - switch (chosenType) { - case HOTSPOT_ONLY: + switch (mTetheringType) { + case TETHERING_TYPE_HOTSPOT_ONLY: return mContext.getString(R.string.tether_settings_summary_hotspot_only); - case USB_ONLY: + case TETHERING_TYPE_USB_ONLY: return mContext.getString(R.string.tether_settings_summary_usb_tethering_only); - case BLUETOOTH_ONLY: + case TETHERING_TYPE_BLUETOOTH_ONLY: return mContext.getString( R.string.tether_settings_summary_bluetooth_tethering_only); - case HOTSPOT_AND_USB: + case TETHERING_TYPE_HOTSPOT_AND_USB: return mContext.getString(R.string.tether_settings_summary_hotspot_and_usb); - case HOTSPOT_AND_BLUETOOTH: + case TETHERING_TYPE_HOTSPOT_AND_BLUETOOTH: return mContext.getString( R.string.tether_settings_summary_hotspot_and_bluetooth); - case USB_AND_BLUETOOTH: + case TETHERING_TYPE_USB_AND_BLUETOOTH: return mContext.getString(R.string.tether_settings_summary_usb_and_bluetooth); - case HOTSPOT_AND_USB_AND_BLUETOOTH: + case TETHERING_TYPE_HOTSPOT_AND_USB_AND_BLUETOOTH: return mContext.getString( R.string.tether_settings_summary_hotspot_and_usb_and_bluetooth); default: @@ -174,14 +164,14 @@ public class AllInOneTetherPreferenceController extends BasePreferenceController @OnLifecycleEvent(Event.ON_RESUME) public void onResume() { if (mTetherEnabler != null) { - mTetherEnabler.setListener(this); + mTetherEnabler.addListener(this); } } @OnLifecycleEvent(Event.ON_PAUSE) public void onPause() { if (mTetherEnabler != null) { - mTetherEnabler.setListener(null); + mTetherEnabler.removeListener(this); } } @@ -206,7 +196,12 @@ public class AllInOneTetherPreferenceController extends BasePreferenceController } @Override - public void onTetherStateUpdated(boolean isTethering) { + public void onTetherStateUpdated(@TetherEnabler.TetheringState int state) { + mTetheringType = 0; + mTetheringType |= TetherEnabler.isBluetoothTethering(state) ? TETHERING_TYPE_BLUETOOTH_ONLY + : 0; + mTetheringType |= TetherEnabler.isWifiTethering(state) ? TETHERING_TYPE_HOTSPOT_ONLY : 0; + mTetheringType |= TetherEnabler.isUsbTethering(state) ? TETHERING_TYPE_USB_ONLY : 0; updateState(mPreference); } } diff --git a/src/com/android/settings/network/BluetoothTetherPreferenceController.java b/src/com/android/settings/network/BluetoothTetherPreferenceController.java index 480cd2641c4..dc66254e126 100644 --- a/src/com/android/settings/network/BluetoothTetherPreferenceController.java +++ b/src/com/android/settings/network/BluetoothTetherPreferenceController.java @@ -21,8 +21,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.SharedPreferences; -import android.net.ConnectivityManager; +import android.net.TetheringManager; import android.text.TextUtils; import android.util.Log; @@ -30,9 +29,6 @@ import androidx.lifecycle.Lifecycle; import androidx.lifecycle.LifecycleObserver; import androidx.lifecycle.OnLifecycleEvent; import androidx.preference.Preference; -import androidx.preference.PreferenceScreen; - -import com.android.settings.core.TogglePreferenceController; import com.google.common.annotations.VisibleForTesting; @@ -40,36 +36,33 @@ import com.google.common.annotations.VisibleForTesting; * This controller helps to manage the switch state and visibility of bluetooth tether switch * preference. It stores preference value when preference changed. */ -public final class BluetoothTetherPreferenceController extends TogglePreferenceController - implements LifecycleObserver, SharedPreferences.OnSharedPreferenceChangeListener { +public final class BluetoothTetherPreferenceController extends TetherBasePreferenceController + implements LifecycleObserver { private static final String TAG = "BluetoothTetherPreferenceController"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - private final ConnectivityManager mCm; private int mBluetoothState; - private Preference mPreference; - private final SharedPreferences mSharedPreferences; + private boolean mBluetoothTethering; - public BluetoothTetherPreferenceController(Context context, String prefKey) { - super(context, prefKey); - mCm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); - mSharedPreferences = - context.getSharedPreferences(TetherEnabler.SHARED_PREF, Context.MODE_PRIVATE); + public BluetoothTetherPreferenceController(Context context, String preferenceKey) { + super(context, preferenceKey); } @Override public boolean isChecked() { - return mSharedPreferences.getBoolean(mPreferenceKey, false); + return mBluetoothTethering; } @Override public boolean setChecked(boolean isChecked) { - if (DEBUG) { - Log.d(TAG, "preference changing to " + isChecked); + if (mTetherEnabler == null) { + return false; + } + if (isChecked) { + mTetherEnabler.startTethering(TetheringManager.TETHERING_BLUETOOTH); + } else { + mTetherEnabler.stopTethering(TetheringManager.TETHERING_BLUETOOTH); } - final SharedPreferences.Editor editor = mSharedPreferences.edit(); - editor.putBoolean(mPreferenceKey, isChecked); - editor.apply(); return true; } @@ -80,27 +73,11 @@ public final class BluetoothTetherPreferenceController extends TogglePreferenceC new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED)); } - @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) - public void onResume() { - mSharedPreferences.registerOnSharedPreferenceChangeListener(this); - } - - @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE) - public void onPause() { - mSharedPreferences.unregisterOnSharedPreferenceChangeListener(this); - } - @OnLifecycleEvent(Lifecycle.Event.ON_STOP) public void onStop() { mContext.unregisterReceiver(mBluetoothChangeReceiver); } - @Override - public void displayPreference(PreferenceScreen screen) { - super.displayPreference(screen); - mPreference = screen.findPreference(mPreferenceKey); - } - @Override public void updateState(Preference preference) { super.updateState(preference); @@ -133,6 +110,12 @@ public final class BluetoothTetherPreferenceController extends TogglePreferenceC } } + @Override + public void onTetherStateUpdated(int state) { + mBluetoothTethering = TetherEnabler.isBluetoothTethering(state); + updateState(mPreference); + } + @VisibleForTesting final BroadcastReceiver mBluetoothChangeReceiver = new BroadcastReceiver() { @Override @@ -144,11 +127,4 @@ public final class BluetoothTetherPreferenceController extends TogglePreferenceC } } }; - - @Override - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { - if (TextUtils.equals(mPreferenceKey, key)) { - updateState(mPreference); - } - } } diff --git a/src/com/android/settings/network/TetherBasePreferenceController.java b/src/com/android/settings/network/TetherBasePreferenceController.java new file mode 100644 index 00000000000..71bf1166b2b --- /dev/null +++ b/src/com/android/settings/network/TetherBasePreferenceController.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.network; + +import android.content.Context; +import android.net.ConnectivityManager; +import android.util.Log; + +import androidx.lifecycle.Lifecycle; +import androidx.lifecycle.LifecycleObserver; +import androidx.lifecycle.OnLifecycleEvent; +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; + +import com.android.settings.core.TogglePreferenceController; + +public abstract class TetherBasePreferenceController extends TogglePreferenceController + implements LifecycleObserver, TetherEnabler.OnTetherStateUpdateListener { + + private static final String TAG = "TetherBasePreferenceController"; + static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + final ConnectivityManager mCm; + + TetherEnabler mTetherEnabler; + Preference mPreference; + + public TetherBasePreferenceController(Context context, String preferenceKey) { + super(context, preferenceKey); + mCm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + } + + /** + * Set TetherEnabler for the controller. Call this method to initialize the controller. + * @param tetherEnabler The tetherEnabler to set for the controller. + */ + public void setTetherEnabler(TetherEnabler tetherEnabler) { + mTetherEnabler = tetherEnabler; + } + + @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) + public void onResume() { + // Must call setEnabler() before + if (mTetherEnabler != null) { + mTetherEnabler.addListener(this); + } + } + + @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE) + public void onPause() { + if (mTetherEnabler != null) { + mTetherEnabler.removeListener(this); + } + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + mPreference = screen.findPreference(mPreferenceKey); + } +} diff --git a/src/com/android/settings/network/TetherEnabler.java b/src/com/android/settings/network/TetherEnabler.java index 9c689bc6668..9cc9c5d67b6 100644 --- a/src/com/android/settings/network/TetherEnabler.java +++ b/src/com/android/settings/network/TetherEnabler.java @@ -31,7 +31,6 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.SharedPreferences; import android.net.ConnectivityManager; import android.net.wifi.WifiManager; import android.os.Handler; @@ -51,21 +50,19 @@ import com.android.settings.widget.SwitchWidgetController; import java.lang.annotation.Retention; import java.lang.ref.WeakReference; import java.util.ArrayList; +import java.util.List; import java.util.concurrent.atomic.AtomicReference; /** - * TetherEnabler is a helper to manage Tethering switch on/off state. It turns on/off - * different types of tethering based on stored values in {@link SharedPreferences} and ensures - * tethering state updated by data saver state. + * TetherEnabler is a helper to manage Tethering switch on/off state. It offers helper functions to + * turn on/off different types of tethering interfaces and ensures tethering state updated by data + * saver state. * * This class is not designed for extending. It's extendable solely for the test purpose. */ public class TetherEnabler implements SwitchWidgetController.OnSwitchChangeListener, - DataSaverBackend.Listener, LifecycleObserver, - SharedPreferences.OnSharedPreferenceChangeListener { - - private OnTetherStateUpdateListener mListener; + DataSaverBackend.Listener, LifecycleObserver { /** * Interface definition for a callback to be invoked when the tethering has been updated. @@ -74,9 +71,9 @@ public class TetherEnabler implements SwitchWidgetController.OnSwitchChangeListe /** * Called when the tethering state has changed. * - * @param isTethering The new tethering state. + * @param state The new tethering state. */ - void onTetherStateUpdated(boolean isTethering); + void onTetherStateUpdated(@TetheringState int state); } private static final String TAG = "TetherEnabler"; @@ -89,12 +86,14 @@ public class TetherEnabler implements SwitchWidgetController.OnSwitchChangeListe value = {TETHERING_OFF, TETHERING_WIFI_ON, TETHERING_USB_ON, TETHERING_BLUETOOTH_ON} ) @interface TetheringState {} - private static final int TETHERING_OFF = 0; - private static final int TETHERING_WIFI_ON = 1; - private static final int TETHERING_USB_ON = 1 << 1; - private static final int TETHERING_BLUETOOTH_ON = 1 << 2; - - public static final String SHARED_PREF = "tether_options"; + @VisibleForTesting + static final int TETHERING_OFF = 0; + @VisibleForTesting + static final int TETHERING_WIFI_ON = 1; + @VisibleForTesting + static final int TETHERING_USB_ON = 1 << 1; + @VisibleForTesting + static final int TETHERING_BLUETOOTH_ON = 1 << 2; // This KEY is used for a shared preference value, not for any displayed preferences. public static final String KEY_ENABLE_WIFI_TETHERING = "enable_wifi_tethering"; @@ -102,19 +101,22 @@ public class TetherEnabler implements SwitchWidgetController.OnSwitchChangeListe public static final String USB_TETHER_KEY = "enable_usb_tethering"; public static final String BLUETOOTH_TETHER_KEY = "enable_bluetooth_tethering" + DEDUP_POSTFIX; + @VisibleForTesting + final List mListeners; private final SwitchWidgetController mSwitchWidgetController; private final WifiManager mWifiManager; private final ConnectivityManager mConnectivityManager; private final DataSaverBackend mDataSaverBackend; private boolean mDataSaverEnabled; + @VisibleForTesting + boolean mBluetoothTetheringStoppedByUser; private final Context mContext; @VisibleForTesting ConnectivityManager.OnStartTetheringCallback mOnStartTetheringCallback; private final AtomicReference mBluetoothPan; - private final SharedPreferences mSharedPreferences; private boolean mBluetoothEnableForTether; private final BluetoothAdapter mBluetoothAdapter; @@ -123,13 +125,13 @@ public class TetherEnabler implements SwitchWidgetController.OnSwitchChangeListe mContext = context; mSwitchWidgetController = switchWidgetController; mDataSaverBackend = new DataSaverBackend(context); - mSharedPreferences = context.getSharedPreferences(SHARED_PREF, Context.MODE_PRIVATE); mConnectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); mBluetoothPan = bluetoothPan; mDataSaverEnabled = mDataSaverBackend.isDataSaverEnabled(); + mListeners = new ArrayList<>(); } @OnLifecycleEvent(Lifecycle.Event.ON_START) @@ -148,38 +150,37 @@ public class TetherEnabler implements SwitchWidgetController.OnSwitchChangeListe updateState(null/*tethered*/); } - @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) - public void onResume() { - mSharedPreferences.registerOnSharedPreferenceChangeListener(this); - } - - @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE) - public void onPause() { - mSharedPreferences.unregisterOnSharedPreferenceChangeListener(this); - } - @OnLifecycleEvent(Lifecycle.Event.ON_STOP) public void onStop() { + mBluetoothTetheringStoppedByUser = false; mDataSaverBackend.remListener(this); mSwitchWidgetController.stopListening(); mContext.unregisterReceiver(mTetherChangeReceiver); } - public void setListener(@Nullable OnTetherStateUpdateListener listener) { - mListener = listener; + public void addListener(OnTetherStateUpdateListener listener) { + if (listener != null && !mListeners.contains(listener)) { + listener.onTetherStateUpdated(getTetheringState(null /* tethered */)); + mListeners.add(listener); + } + } + + public void removeListener(OnTetherStateUpdateListener listener) { + if (listener != null) { + mListeners.remove(listener); + } } @VisibleForTesting void updateState(@Nullable String[] tethered) { - int tetherState = getTetheringState(tethered); + int state = getTetheringState(tethered); if (DEBUG) { - Log.d(TAG, "updateState: " + tetherState); + Log.d(TAG, "updateState: " + state); } - setSwitchCheckedInternal(tetherState != TETHERING_OFF); - setSharedPreferencesInternal(tetherState); + setSwitchCheckedInternal(state != TETHERING_OFF); mSwitchWidgetController.setEnabled(!mDataSaverEnabled); - if (mListener != null) { - mListener.onTetherStateUpdated(tetherState != TETHERING_OFF); + for (int i = 0, size = mListeners.size(); i < size; ++i) { + mListeners.get(i).onTetherStateUpdated(state); } } @@ -189,33 +190,24 @@ public class TetherEnabler implements SwitchWidgetController.OnSwitchChangeListe mSwitchWidgetController.startListening(); } - private void setSharedPreferencesInternal(@TetheringState int tetherState) { - if (tetherState == TETHERING_OFF) { - // We don't override user's preferences when tethering off. - return; - } - mSharedPreferences.unregisterOnSharedPreferenceChangeListener(this); - final SharedPreferences.Editor editor = mSharedPreferences.edit(); - editor.putBoolean(KEY_ENABLE_WIFI_TETHERING, (tetherState & TETHERING_WIFI_ON) != 0); - editor.putBoolean(USB_TETHER_KEY, (tetherState & TETHERING_USB_ON) != 0); - editor.putBoolean(BLUETOOTH_TETHER_KEY, (tetherState & TETHERING_BLUETOOTH_ON) != 0); - editor.commit(); - mSharedPreferences.registerOnSharedPreferenceChangeListener(this); - } - - private @TetheringState int getTetheringState(@Nullable String[] tethered) { + @VisibleForTesting + @TetheringState int getTetheringState(@Nullable String[] tethered) { int tetherState = TETHERING_OFF; if (tethered == null) { tethered = mConnectivityManager.getTetheredIfaces(); } - if (mWifiManager.getWifiApState() == WifiManager.WIFI_AP_STATE_ENABLED) { + if (mWifiManager.isWifiApEnabled()) { tetherState |= TETHERING_WIFI_ON; } - final BluetoothPan pan = mBluetoothPan.get(); - if (pan != null && pan.isTetheringOn()) { - tetherState |= TETHERING_BLUETOOTH_ON; + // Only check bluetooth tethering state if not stopped by user already. + if (!mBluetoothTetheringStoppedByUser) { + final BluetoothPan pan = mBluetoothPan.get(); + if (mBluetoothAdapter.getState() == BluetoothAdapter.STATE_ON + && pan != null && pan.isTetheringOn()) { + tetherState |= TETHERING_BLUETOOTH_ON; + } } String[] usbRegexs = mConnectivityManager.getTetherableUsbRegexs(); @@ -230,79 +222,58 @@ public class TetherEnabler implements SwitchWidgetController.OnSwitchChangeListe return tetherState; } + public static boolean isBluetoothTethering(@TetheringState int state) { + return (state & TETHERING_BLUETOOTH_ON) != TETHERING_OFF; + } + + public static boolean isUsbTethering(@TetheringState int state) { + return (state & TETHERING_USB_ON) != TETHERING_OFF; + } + + public static boolean isWifiTethering(@TetheringState int state) { + return (state & TETHERING_WIFI_ON) != TETHERING_OFF; + } + @Override public boolean onSwitchToggled(boolean isChecked) { - if (isChecked && getTetheringState(null /* tethered */) == TETHERING_OFF) { - startTether(); - } - - if (!isChecked && getTetheringState(null /* tethered */) != TETHERING_OFF) { - stopTether(); + if (isChecked) { + startTethering(TETHERING_WIFI); + } else { + stopTethering(TETHERING_USB); + stopTethering(TETHERING_WIFI); + stopTethering(TETHERING_BLUETOOTH); } return true; } - private void stopTether() { - - // Wi-Fi tether is selected by default. - if (mSharedPreferences.getBoolean(KEY_ENABLE_WIFI_TETHERING, true)) { - stopTethering(TETHERING_WIFI); - } - - if (mSharedPreferences.getBoolean(USB_TETHER_KEY, false)) { - stopTethering(TETHERING_USB); - } - - if (mSharedPreferences.getBoolean(BLUETOOTH_TETHER_KEY, false)) { - stopTethering(TETHERING_BLUETOOTH); - } - } - - /** - * Use this method to stop a single choice of tethering. - * - * @param choice The choice of tethering to stop. - */ public void stopTethering(int choice) { - mConnectivityManager.stopTethering(choice); - } - - @VisibleForTesting - void startTether() { - - // Wi-Fi tether is selected by default. - if (mSharedPreferences.getBoolean(KEY_ENABLE_WIFI_TETHERING, true)) { - startTethering(TETHERING_WIFI); - } - - if (mSharedPreferences.getBoolean(USB_TETHER_KEY, false)) { - startTethering(TETHERING_USB); - } - - if (mSharedPreferences.getBoolean(BLUETOOTH_TETHER_KEY, false)) { - startTethering(TETHERING_BLUETOOTH); - } - } - - /** - * Use this method to start a single choice of tethering. - * For bluetooth tethering, it will first turn on bluetooth if bluetooth is off. - * For Wi-Fi tethering, it will be no-op if Wi-Fi tethering already active. - * - * @param choice The choice of tethering to start. - */ - public void startTethering(int choice) { - mSwitchWidgetController.setEnabled(false); - - if (choice == TETHERING_WIFI && mWifiManager.isWifiApEnabled()) { - if (DEBUG) { - Log.d(TAG, "Wifi tether already active!"); + int state = getTetheringState(null /* tethered */); + if ((choice == TETHERING_WIFI && isWifiTethering(state)) + || (choice == TETHERING_USB && isUsbTethering(state)) + || (choice == TETHERING_BLUETOOTH && isBluetoothTethering(state))) { + mSwitchWidgetController.setEnabled(false); + mConnectivityManager.stopTethering(choice); + if (choice == TETHERING_BLUETOOTH) { + // Stop bluetooth tether won't invoke tether state changed callback, so we need this + // boolean to remember the user action and update UI state immediately. + mBluetoothTetheringStoppedByUser = true; + updateState(null /* tethered */); } + } + } + + public void startTethering(int choice) { + int state = getTetheringState(null /* tethered */); + if ((choice == TETHERING_WIFI && isWifiTethering(state)) + || (choice == TETHERING_USB && isUsbTethering(state))) { return; } if (choice == TETHERING_BLUETOOTH) { - if (mBluetoothAdapter.getState() == BluetoothAdapter.STATE_OFF) { + mBluetoothTetheringStoppedByUser = false; + if (isBluetoothTethering(state)) { + return; + } else if (mBluetoothAdapter.getState() == BluetoothAdapter.STATE_OFF) { if (DEBUG) { Log.d(TAG, "Turn on bluetooth first."); } @@ -312,6 +283,7 @@ public class TetherEnabler implements SwitchWidgetController.OnSwitchChangeListe } } + mSwitchWidgetController.setEnabled(false); mConnectivityManager.startTethering(choice, true /* showProvisioningUi */, mOnStartTetheringCallback, new Handler(Looper.getMainLooper())); } @@ -392,32 +364,6 @@ public class TetherEnabler implements SwitchWidgetController.OnSwitchChangeListe // we don't care, since we just want to read the value } - @Override - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { - if (!mSwitchWidgetController.isChecked()) { - return; - } - if (TextUtils.equals(KEY_ENABLE_WIFI_TETHERING, key)) { - if (sharedPreferences.getBoolean(key, true)) { - startTethering(TETHERING_WIFI); - } else { - mConnectivityManager.stopTethering(TETHERING_WIFI); - } - } else if (TextUtils.equals(USB_TETHER_KEY, key)) { - if (sharedPreferences.getBoolean(key, false)) { - startTethering(TETHERING_USB); - } else { - mConnectivityManager.stopTethering(TETHERING_USB); - } - } else if (TextUtils.equals(BLUETOOTH_TETHER_KEY, key)) { - if (sharedPreferences.getBoolean(key, false)) { - startTethering(TETHERING_BLUETOOTH); - } else { - mConnectivityManager.stopTethering(TETHERING_BLUETOOTH); - } - } - } - private static final class OnStartTetheringCallback extends ConnectivityManager.OnStartTetheringCallback { final WeakReference mTetherEnabler; diff --git a/src/com/android/settings/network/UsbTetherPreferenceController.java b/src/com/android/settings/network/UsbTetherPreferenceController.java index 7305a482d43..a3a42936762 100644 --- a/src/com/android/settings/network/UsbTetherPreferenceController.java +++ b/src/com/android/settings/network/UsbTetherPreferenceController.java @@ -20,60 +20,52 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.SharedPreferences; import android.hardware.usb.UsbManager; -import android.net.ConnectivityManager; +import android.net.TetheringManager; import android.os.Environment; import android.text.TextUtils; -import android.util.Log; +import androidx.annotation.VisibleForTesting; import androidx.lifecycle.Lifecycle; import androidx.lifecycle.LifecycleObserver; import androidx.lifecycle.OnLifecycleEvent; import androidx.preference.Preference; -import androidx.preference.PreferenceScreen; -import com.android.internal.annotations.VisibleForTesting; import com.android.settings.Utils; -import com.android.settings.core.TogglePreferenceController; /** * This controller helps to manage the switch state and visibility of USB tether switch * preference. It stores preference values when preference changed. * */ -public final class UsbTetherPreferenceController extends TogglePreferenceController implements - LifecycleObserver, SharedPreferences.OnSharedPreferenceChangeListener { +public final class UsbTetherPreferenceController extends TetherBasePreferenceController implements + LifecycleObserver { private static final String TAG = "UsbTetherPrefController"; - private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - private final ConnectivityManager mCm; private boolean mUsbConnected; private boolean mMassStorageActive; - private Preference mPreference; - private final SharedPreferences mSharedPreferences; + private boolean mUsbTethering; public UsbTetherPreferenceController(Context context, String prefKey) { super(context, prefKey); - mCm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); - mSharedPreferences = - context.getSharedPreferences(TetherEnabler.SHARED_PREF, Context.MODE_PRIVATE); } @Override public boolean isChecked() { - return mSharedPreferences.getBoolean(mPreferenceKey, false); + return mUsbTethering; } @Override public boolean setChecked(boolean isChecked) { - if (DEBUG) { - Log.d(TAG, "preference changing to " + isChecked); + if (mTetherEnabler == null) { + return false; + } + if (isChecked) { + mTetherEnabler.startTethering(TetheringManager.TETHERING_USB); + } else { + mTetherEnabler.stopTethering(TetheringManager.TETHERING_USB); } - final SharedPreferences.Editor editor = mSharedPreferences.edit(); - editor.putBoolean(mPreferenceKey, isChecked); - editor.apply(); return true; } @@ -86,17 +78,6 @@ public final class UsbTetherPreferenceController extends TogglePreferenceControl mContext.registerReceiver(mUsbChangeReceiver, filter); } - - @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) - public void onResume() { - mSharedPreferences.registerOnSharedPreferenceChangeListener(this); - } - - @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE) - public void onPause() { - mSharedPreferences.unregisterOnSharedPreferenceChangeListener(this); - } - @OnLifecycleEvent(Lifecycle.Event.ON_STOP) public void onStop() { mContext.unregisterReceiver(mUsbChangeReceiver); @@ -112,12 +93,6 @@ public final class UsbTetherPreferenceController extends TogglePreferenceControl } } - @Override - public void displayPreference(PreferenceScreen screen) { - super.displayPreference(screen); - mPreference = screen.findPreference(mPreferenceKey); - } - @Override public void updateState(Preference preference) { super.updateState(preference); @@ -126,6 +101,12 @@ public final class UsbTetherPreferenceController extends TogglePreferenceControl } } + @Override + public void onTetherStateUpdated(int state) { + mUsbTethering = TetherEnabler.isUsbTethering(state); + updateState(mPreference); + } + @VisibleForTesting final BroadcastReceiver mUsbChangeReceiver = new BroadcastReceiver() { @Override @@ -141,11 +122,4 @@ public final class UsbTetherPreferenceController extends TogglePreferenceControl updateState(mPreference); } }; - - @Override - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { - if (TextUtils.equals(mPreferenceKey, key)) { - updateState(mPreference); - } - } } diff --git a/src/com/android/settings/network/WifiTetherDisablePreferenceController.java b/src/com/android/settings/network/WifiTetherDisablePreferenceController.java index 2650b8ba094..544a886d12e 100644 --- a/src/com/android/settings/network/WifiTetherDisablePreferenceController.java +++ b/src/com/android/settings/network/WifiTetherDisablePreferenceController.java @@ -17,21 +17,14 @@ package com.android.settings.network; import android.content.Context; -import android.content.SharedPreferences; -import android.net.ConnectivityManager; -import android.text.TextUtils; -import android.util.Log; +import android.net.TetheringManager; -import androidx.lifecycle.Lifecycle; import androidx.lifecycle.LifecycleObserver; -import androidx.lifecycle.OnLifecycleEvent; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; -import androidx.preference.SwitchPreference; import com.android.internal.annotations.VisibleForTesting; import com.android.settings.R; -import com.android.settings.core.TogglePreferenceController; import com.android.settingslib.TetherUtil; /** @@ -43,61 +36,41 @@ import com.android.settingslib.TetherUtil; * @see BluetoothTetherPreferenceController * @see UsbTetherPreferenceController */ -public final class WifiTetherDisablePreferenceController extends TogglePreferenceController - implements LifecycleObserver, SharedPreferences.OnSharedPreferenceChangeListener { +public final class WifiTetherDisablePreferenceController extends TetherBasePreferenceController + implements LifecycleObserver { private static final String TAG = "WifiTetherDisablePreferenceController"; - private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - private final ConnectivityManager mCm; - private boolean mBluetoothTetherEnabled; - private boolean mUSBTetherEnabled; + private boolean mBluetoothTethering; + private boolean mUsbTethering; + private boolean mWifiTethering; private PreferenceScreen mScreen; - private Preference mPreference; - private final SharedPreferences mSharedPreferences; public WifiTetherDisablePreferenceController(Context context, String prefKey) { super(context, prefKey); - mSharedPreferences = - context.getSharedPreferences(TetherEnabler.SHARED_PREF, Context.MODE_PRIVATE); - mCm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); - mUSBTetherEnabled = mSharedPreferences.getBoolean( - TetherEnabler.USB_TETHER_KEY, false); - mBluetoothTetherEnabled = mSharedPreferences.getBoolean( - TetherEnabler.BLUETOOTH_TETHER_KEY, false); } @Override public boolean isChecked() { - return !mSharedPreferences.getBoolean(TetherEnabler.KEY_ENABLE_WIFI_TETHERING, true); + return !mWifiTethering; } @Override public boolean setChecked(boolean isChecked) { - // The shared preference's value is in the opposite of this preference's value. - final boolean enableWifi = !isChecked; - if (DEBUG) { - Log.d(TAG, "check state changing to " + isChecked); + if (mTetherEnabler == null) { + return false; + } + if (isChecked) { + mTetherEnabler.stopTethering(TetheringManager.TETHERING_WIFI); + } else { + mTetherEnabler.startTethering(TetheringManager.TETHERING_WIFI); } - final SharedPreferences.Editor editor = mSharedPreferences.edit(); - editor.putBoolean(TetherEnabler.KEY_ENABLE_WIFI_TETHERING, enableWifi); - editor.apply(); return true; } - @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) - public void onResume() { - mSharedPreferences.registerOnSharedPreferenceChangeListener(this); - } - - @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE) - public void onPause() { - mSharedPreferences.unregisterOnSharedPreferenceChangeListener(this); - } - @VisibleForTesting boolean shouldShow() { - return mBluetoothTetherEnabled || mUSBTetherEnabled; + return mBluetoothTethering || mUsbTethering; } @Override @@ -113,11 +86,11 @@ public final class WifiTetherDisablePreferenceController extends TogglePreferenc @Override public CharSequence getSummary() { - if (mUSBTetherEnabled && mBluetoothTetherEnabled) { + if (mUsbTethering && mBluetoothTethering) { return mContext.getString(R.string.disable_wifi_hotspot_when_usb_and_bluetooth_on); - } else if (mUSBTetherEnabled) { + } else if (mUsbTethering) { return mContext.getString(R.string.disable_wifi_hotspot_when_usb_on); - } else if (mBluetoothTetherEnabled) { + } else if (mBluetoothTethering) { return mContext.getString(R.string.disable_wifi_hotspot_when_bluetooth_on); } return mContext.getString(R.string.summary_placeholder); @@ -127,7 +100,6 @@ public final class WifiTetherDisablePreferenceController extends TogglePreferenc public void displayPreference(PreferenceScreen screen) { super.displayPreference(screen); mScreen = screen; - mPreference = screen.findPreference(mPreferenceKey); if (mPreference != null) { mPreference.setOnPreferenceChangeListener(this); } @@ -141,42 +113,10 @@ public final class WifiTetherDisablePreferenceController extends TogglePreferenc } @Override - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, - String key) { - final boolean shouldShowBefore = shouldShow(); - if (TextUtils.equals(TetherEnabler.KEY_ENABLE_WIFI_TETHERING, key) && shouldShowBefore) { - updateState(mPreference); - return; - } - - boolean shouldUpdateState = false; - if (TextUtils.equals(TetherEnabler.USB_TETHER_KEY, key)) { - mUSBTetherEnabled = sharedPreferences.getBoolean(key, false); - shouldUpdateState = true; - } else if (TextUtils.equals(TetherEnabler.BLUETOOTH_TETHER_KEY, key)) { - mBluetoothTetherEnabled = sharedPreferences.getBoolean(key, false); - shouldUpdateState = true; - } - - // Check if we are hiding this preference. If so, make sure the preference is set to - // unchecked to enable wifi tether. - if (mPreference != null && mPreference instanceof SwitchPreference - && shouldShowBefore && !shouldShow()) { - final SwitchPreference switchPreference = (SwitchPreference) mPreference; - if (switchPreference.isChecked()) { - if (DEBUG) { - Log.d(TAG, - "All other types are unchecked, wifi tether enabled automatically"); - } - // Need to call this method before internal state set. - if (switchPreference.callChangeListener(false)) { - switchPreference.setChecked(false); - } - } - } - - if (shouldUpdateState) { - updateState(mPreference); - } + public void onTetherStateUpdated(int state) { + mUsbTethering = TetherEnabler.isUsbTethering(state); + mBluetoothTethering = TetherEnabler.isBluetoothTethering(state); + mWifiTethering = TetherEnabler.isWifiTethering(state); + updateState(mPreference); } } diff --git a/tests/robotests/src/com/android/settings/network/AllInOneTetherPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/AllInOneTetherPreferenceControllerTest.java index c74e669f009..282a1709aac 100644 --- a/tests/robotests/src/com/android/settings/network/AllInOneTetherPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/network/AllInOneTetherPreferenceControllerTest.java @@ -26,7 +26,6 @@ import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothPan; import android.bluetooth.BluetoothProfile; import android.content.Context; -import android.content.SharedPreferences; import com.android.settings.widget.MasterSwitchPreference; @@ -49,8 +48,6 @@ public class AllInOneTetherPreferenceControllerTest { private BluetoothAdapter mBluetoothAdapter; @Mock private MasterSwitchPreference mPreference; - @Mock - private SharedPreferences mSharedPreferences; private AllInOneTetherPreferenceController mController; @@ -61,8 +58,6 @@ public class AllInOneTetherPreferenceControllerTest { ReflectionHelpers.setField(mController, "mContext", mContext); ReflectionHelpers.setField(mController, "mBluetoothAdapter", mBluetoothAdapter); ReflectionHelpers.setField(mController, "mPreference", mPreference); - ReflectionHelpers - .setField(mController, "mTetherEnablerSharedPreferences", mSharedPreferences); } @Test diff --git a/tests/robotests/src/com/android/settings/network/BluetoothTetherPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/BluetoothTetherPreferenceControllerTest.java index fc180a289dc..bab82ef250c 100644 --- a/tests/robotests/src/com/android/settings/network/BluetoothTetherPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/network/BluetoothTetherPreferenceControllerTest.java @@ -27,8 +27,8 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; -import android.content.SharedPreferences; import android.net.ConnectivityManager; +import android.net.TetheringManager; import androidx.preference.SwitchPreference; import androidx.test.core.app.ApplicationProvider; @@ -47,7 +47,7 @@ public class BluetoothTetherPreferenceControllerTest { @Mock private ConnectivityManager mConnectivityManager; @Mock - private SharedPreferences mSharedPreferences; + private TetherEnabler mTetherEnabler; private SwitchPreference mSwitchPreference; private BluetoothTetherPreferenceController mController; @@ -61,10 +61,9 @@ public class BluetoothTetherPreferenceControllerTest { mSwitchPreference = spy(SwitchPreference.class); when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn( mConnectivityManager); - when(mContext.getSharedPreferences(TetherEnabler.SHARED_PREF, Context.MODE_PRIVATE)) - .thenReturn(mSharedPreferences); when(mConnectivityManager.getTetherableBluetoothRegexs()).thenReturn(new String[] {""}); mController = new BluetoothTetherPreferenceController(mContext, BLUETOOTH_TETHER_KEY); + mController.setTetherEnabler(mTetherEnabler); ReflectionHelpers.setField(mController, "mPreference", mSwitchPreference); } @@ -77,6 +76,18 @@ public class BluetoothTetherPreferenceControllerTest { any()); } + @Test + public void lifecycle_shouldAddListenerOnResume() { + mController.onResume(); + verify(mTetherEnabler).addListener(mController); + } + + @Test + public void lifecycle_shouldRemoveListenrOnPause() { + mController.onPause(); + verify(mTetherEnabler).removeListener(mController); + } + @Test public void lifecycle_shouldUnregisterReceiverOnStop() { mController.onStart(); @@ -96,18 +107,26 @@ public class BluetoothTetherPreferenceControllerTest { } @Test - public void switch_shouldCheckedWhenSharedPreferenceIsTrue() { - when(mSharedPreferences.getBoolean(BLUETOOTH_TETHER_KEY, false)).thenReturn(true); - mController.onSharedPreferenceChanged(mSharedPreferences, BLUETOOTH_TETHER_KEY); - - verify(mSwitchPreference).setChecked(true); + public void setChecked_shouldStartBluetoothTethering() { + mController.setChecked(true); + verify(mTetherEnabler).startTethering(TetheringManager.TETHERING_BLUETOOTH); } @Test - public void switch_shouldUnCheckedWhenSharedPreferenceIsFalse() { - when(mSharedPreferences.getBoolean(BLUETOOTH_TETHER_KEY, false)).thenReturn(false); - mController.onSharedPreferenceChanged(mSharedPreferences, BLUETOOTH_TETHER_KEY); + public void setUnchecked_shouldStopBluetoothTethering() { + mController.setChecked(false); + verify(mTetherEnabler).stopTethering(TetheringManager.TETHERING_BLUETOOTH); + } - verify(mSwitchPreference).setChecked(false); + @Test + public void switch_shouldCheckedWhenBluetoothTethering() { + mController.onTetherStateUpdated(TetherEnabler.TETHERING_BLUETOOTH_ON); + assertThat(mController.isChecked()).isTrue(); + } + + @Test + public void switch_shouldUnCheckedWhenBluetoothNotTethering() { + mController.onTetherStateUpdated(TetherEnabler.TETHERING_OFF); + assertThat(mController.isChecked()).isFalse(); } } diff --git a/tests/robotests/src/com/android/settings/network/TetherEnablerTest.java b/tests/robotests/src/com/android/settings/network/TetherEnablerTest.java index 22e35fdd550..29d07afc859 100644 --- a/tests/robotests/src/com/android/settings/network/TetherEnablerTest.java +++ b/tests/robotests/src/com/android/settings/network/TetherEnablerTest.java @@ -32,13 +32,14 @@ import static org.mockito.Mockito.when; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothPan; import android.content.Context; -import android.content.SharedPreferences; import android.net.ConnectivityManager; import android.net.NetworkPolicyManager; +import android.net.TetheringManager; import android.net.wifi.WifiManager; import androidx.test.core.app.ApplicationProvider; +import com.android.settings.network.TetherEnabler.OnTetherStateUpdateListener; import com.android.settings.widget.SwitchBar; import com.android.settings.widget.SwitchBarController; import com.android.settings.widget.SwitchWidgetController; @@ -51,6 +52,8 @@ import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.util.ReflectionHelpers; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.atomic.AtomicReference; @RunWith(RobolectricTestRunner.class) @@ -64,7 +67,7 @@ public class TetherEnablerTest { @Mock private BluetoothPan mBluetoothPan; @Mock - private SharedPreferences mSharedPreferences; + private BluetoothAdapter mBluetoothAdapter; private SwitchBar mSwitchBar; private TetherEnabler mEnabler; @@ -88,22 +91,8 @@ public class TetherEnablerTest { when(mConnectivityManager.getTetheredIfaces()).thenReturn(new String[0]); when(mConnectivityManager.getTetherableUsbRegexs()).thenReturn(new String[0]); panReference.set(mBluetoothPan); - when(context.getSharedPreferences(TetherEnabler.SHARED_PREF, Context.MODE_PRIVATE)) - .thenReturn(mSharedPreferences); - SharedPreferences.Editor editor = mock(SharedPreferences.Editor.class); - when(mSharedPreferences.edit()).thenReturn(editor); mEnabler = spy(new TetherEnabler(context, mSwitchWidgetController, panReference)); - } - - @Test - public void lifecycle_onPause_unRegisterSharedPreferenceListener() { - mEnabler.onResume(); - verify(mSharedPreferences).registerOnSharedPreferenceChangeListener( - eq(mEnabler)); - - mEnabler.onPause(); - verify(mSharedPreferences).unregisterOnSharedPreferenceChangeListener( - eq(mEnabler)); + ReflectionHelpers.setField(mEnabler, "mBluetoothAdapter", mBluetoothAdapter); } @Test @@ -115,11 +104,20 @@ public class TetherEnablerTest { assertThat(mSwitchBar.isChecked()).isTrue(); } + @Test + public void lifecycle_onStop_resetBluetoothTetheringStoppedByUser() { + mEnabler.onStart(); + mEnabler.mBluetoothTetheringStoppedByUser = true; + + mEnabler.onStop(); + assertThat(mEnabler.mBluetoothTetheringStoppedByUser).isFalse(); + } + @Test public void startTether_fail_resetSwitchBar() { when(mNetworkPolicyManager.getRestrictBackground()).thenReturn(false); mEnabler.onStart(); - mEnabler.startTether(); + mEnabler.startTethering(TetheringManager.TETHERING_WIFI); when(mConnectivityManager.getTetheredIfaces()).thenReturn(new String[0]); mEnabler.mOnStartTetheringCallback.onTetheringFailed(); @@ -145,8 +143,6 @@ public class TetherEnablerTest { @Test public void onSwitchToggled_onlyStartsWifiTetherWhenNeeded() { - when(mSharedPreferences.getBoolean(TetherEnabler.KEY_ENABLE_WIFI_TETHERING, true)) - .thenReturn(true); when(mWifiManager.isWifiApEnabled()).thenReturn(true); mEnabler.onSwitchToggled(true); verify(mConnectivityManager, never()).startTethering(anyInt(), anyBoolean(), any(), any()); @@ -157,36 +153,28 @@ public class TetherEnablerTest { } @Test - public void onSwitchToggled_shouldStartUSBTetherWhenSelected() { - SharedPreferences preference = mock(SharedPreferences.class); - ReflectionHelpers.setField(mEnabler, "mSharedPreferences", preference); - when(preference.getBoolean(TetherEnabler.KEY_ENABLE_WIFI_TETHERING, true)) - .thenReturn(false); - when(preference.getBoolean(TetherEnabler.USB_TETHER_KEY, false)).thenReturn(true); - when(preference.getBoolean(TetherEnabler.BLUETOOTH_TETHER_KEY, true)).thenReturn(false); + public void startTethering_startsBluetoothTetherWhenOff() { + when(mBluetoothAdapter.getState()).thenReturn(BluetoothAdapter.STATE_OFF); - mEnabler.startTether(); + mEnabler.startTethering(ConnectivityManager.TETHERING_BLUETOOTH); + verify(mBluetoothAdapter).enable(); + + when(mBluetoothAdapter.getState()).thenReturn(BluetoothAdapter.STATE_ON); + mEnabler.startTethering(ConnectivityManager.TETHERING_BLUETOOTH); verify(mConnectivityManager).startTethering( - eq(ConnectivityManager.TETHERING_USB), anyBoolean(), any(), any()); - verify(mConnectivityManager, never()) - .startTethering(eq(ConnectivityManager.TETHERING_WIFI), anyBoolean(), any(), any()); - verify(mConnectivityManager, never()).startTethering( eq(ConnectivityManager.TETHERING_BLUETOOTH), anyBoolean(), any(), any()); } @Test - public void startTether_startsBluetoothTetherWhenOff() { - BluetoothAdapter adapter = mock(BluetoothAdapter.class); - ReflectionHelpers.setField(mEnabler, "mBluetoothAdapter", adapter); - when(adapter.getState()).thenReturn(BluetoothAdapter.STATE_OFF); + public void stopTethering_setBluetoothTetheringStoppedByUserAndUpdateState() { + mSwitchWidgetController.setListener(mEnabler); + mSwitchWidgetController.startListening(); + int state = TetherEnabler.TETHERING_BLUETOOTH_ON; + doReturn(state).when(mEnabler).getTetheringState(null /* tethered */); - mEnabler.startTethering(ConnectivityManager.TETHERING_BLUETOOTH); - verify(adapter).enable(); - - when(adapter.getState()).thenReturn(BluetoothAdapter.STATE_ON); - mEnabler.startTethering(ConnectivityManager.TETHERING_BLUETOOTH); - verify(mConnectivityManager).startTethering( - eq(ConnectivityManager.TETHERING_BLUETOOTH), anyBoolean(), any(), any()); + mEnabler.stopTethering(TetheringManager.TETHERING_BLUETOOTH); + assertThat(mEnabler.mBluetoothTetheringStoppedByUser).isTrue(); + verify(mEnabler).updateState(null); } @Test @@ -210,35 +198,44 @@ public class TetherEnablerTest { @Test public void updateState_shouldEnableSwitchBarTethering() { + when(mConnectivityManager.getTetheredIfaces()).thenReturn(USB_TETHERED); + when(mConnectivityManager.getTetherableUsbRegexs()).thenReturn(USB_TETHERED); + mSwitchWidgetController.setListener(mEnabler); mSwitchWidgetController.startListening(); ReflectionHelpers.setField(mEnabler, "mDataSaverEnabled", false); - mEnabler.updateState(new String[]{""}); + mEnabler.updateState(null/*tethered*/); verify(mSwitchBar).setEnabled(true); } @Test - public void updateState_onSharedPreferencesChangeNeverCalled() { - mSharedPreferences.registerOnSharedPreferenceChangeListener(mEnabler); + public void updateState_shouldCallListener() { + OnTetherStateUpdateListener listener = mock( + OnTetherStateUpdateListener.class); + List listeners = new ArrayList<>(); + listeners.add(listener); + ReflectionHelpers.setField(mEnabler, "mListeners", listeners); mSwitchWidgetController.setListener(mEnabler); mSwitchWidgetController.startListening(); mEnabler.updateState(null /* tethered */); - verify(mEnabler, never()).onSharedPreferenceChanged(eq(mSharedPreferences), any()); - verify(mEnabler, never()).onSharedPreferenceChanged(eq(mSharedPreferences), any()); + verify(listener).onTetherStateUpdated(anyInt()); } @Test - public void updateState_setSharedPreferencesOnlyWhenNeeded() { - mSwitchWidgetController.setListener(mEnabler); - mSwitchWidgetController.startListening(); - - mEnabler.updateState(null /* tethered */); - verify(mSharedPreferences, never()).edit(); - - when(mConnectivityManager.getTetherableUsbRegexs()).thenReturn(USB_TETHERED); - mSharedPreferences.registerOnSharedPreferenceChangeListener(mEnabler); - mEnabler.updateState(USB_TETHERED); + public void addListener_listenerShouldAdded() { + OnTetherStateUpdateListener listener = mock( + OnTetherStateUpdateListener.class); + mEnabler.addListener(listener); + assertThat(mEnabler.mListeners).contains(listener); } -} + + @Test + public void remListener_listenerShouldBeRemoved() { + OnTetherStateUpdateListener listener = mock( + OnTetherStateUpdateListener.class); + mEnabler.removeListener(listener); + assertThat(mEnabler.mListeners).doesNotContain(listener); + } +} \ No newline at end of file diff --git a/tests/robotests/src/com/android/settings/network/UsbTetherPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/UsbTetherPreferenceControllerTest.java index ce9da47ed0c..fbb98a4f471 100644 --- a/tests/robotests/src/com/android/settings/network/UsbTetherPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/network/UsbTetherPreferenceControllerTest.java @@ -27,8 +27,8 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; -import android.content.SharedPreferences; import android.net.ConnectivityManager; +import android.net.TetheringManager; import androidx.preference.SwitchPreference; import androidx.test.core.app.ApplicationProvider; @@ -47,7 +47,7 @@ public class UsbTetherPreferenceControllerTest { @Mock private ConnectivityManager mConnectivityManager; @Mock - private SharedPreferences mSharedPreferences; + private TetherEnabler mTetherEnabler; private Context mContext; private UsbTetherPreferenceController mController; @@ -61,9 +61,8 @@ public class UsbTetherPreferenceControllerTest { when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn( mConnectivityManager); when(mConnectivityManager.getTetherableUsbRegexs()).thenReturn(new String[]{""}); - when(mContext.getSharedPreferences(TetherEnabler.SHARED_PREF, Context.MODE_PRIVATE)) - .thenReturn(mSharedPreferences); mController = new UsbTetherPreferenceController(mContext, USB_TETHER_KEY); + mController.setTetherEnabler(mTetherEnabler); mSwitchPreference = spy(SwitchPreference.class); ReflectionHelpers.setField(mController, "mPreference", mSwitchPreference); } @@ -75,6 +74,18 @@ public class UsbTetherPreferenceControllerTest { verify(mContext).registerReceiver(eq(mController.mUsbChangeReceiver), any()); } + @Test + public void lifecycle_shouldAddListenerOnResume() { + mController.onResume(); + verify(mTetherEnabler).addListener(mController); + } + + @Test + public void lifecycle_shouldRemoveListenrOnPause() { + mController.onPause(); + verify(mTetherEnabler).removeListener(mController); + } + @Test public void lifecycle_shouldUnregisterReceiverOnStop() { mController.onStart(); @@ -93,18 +104,26 @@ public class UsbTetherPreferenceControllerTest { } @Test - public void switch_shouldCheckedWhenSharedPreferencesIsTrue() { - when(mSharedPreferences.getBoolean(USB_TETHER_KEY, false)).thenReturn(true); - mController.onSharedPreferenceChanged(mSharedPreferences, USB_TETHER_KEY); - - verify(mSwitchPreference).setChecked(true); + public void setChecked_shouldStartUsbTethering() { + mController.setChecked(true); + verify(mTetherEnabler).startTethering(TetheringManager.TETHERING_USB); } @Test - public void switch_shouldUnCheckedWhenSharedPreferencesIsFalse() { - when(mSharedPreferences.getBoolean(USB_TETHER_KEY, false)).thenReturn(false); - mController.onSharedPreferenceChanged(mSharedPreferences, USB_TETHER_KEY); + public void setUnchecked_shouldStopUsbTethering() { + mController.setChecked(false); + verify(mTetherEnabler).stopTethering(TetheringManager.TETHERING_USB); + } - verify(mSwitchPreference).setChecked(false); + @Test + public void switch_shouldCheckedWhenUsbTethering() { + mController.onTetherStateUpdated(TetherEnabler.TETHERING_USB_ON); + assertThat(mController.isChecked()).isTrue(); + } + + @Test + public void switch_shouldUnCheckedWhenUsbNotTethering() { + mController.onTetherStateUpdated(TetherEnabler.TETHERING_OFF); + assertThat(mController.isChecked()).isFalse(); } } diff --git a/tests/robotests/src/com/android/settings/network/WifiTetherDisablePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/WifiTetherDisablePreferenceControllerTest.java index ebb99020168..211f9329985 100644 --- a/tests/robotests/src/com/android/settings/network/WifiTetherDisablePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/network/WifiTetherDisablePreferenceControllerTest.java @@ -16,20 +16,16 @@ package com.android.settings.network; -import static com.android.settings.network.TetherEnabler.BLUETOOTH_TETHER_KEY; -import static com.android.settings.network.TetherEnabler.USB_TETHER_KEY; import static com.android.settings.network.TetherEnabler.WIFI_TETHER_DISABLE_KEY; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; -import android.content.SharedPreferences; import android.net.ConnectivityManager; import androidx.preference.PreferenceScreen; @@ -50,9 +46,9 @@ public class WifiTetherDisablePreferenceControllerTest { @Mock private ConnectivityManager mConnectivityManager; @Mock - private SharedPreferences mSharedPreferences; - @Mock private PreferenceScreen mPreferenceScreen; + @Mock + private TetherEnabler mTetherEnabler; private SwitchPreference mPreference; private Context mContext; @@ -67,60 +63,40 @@ public class WifiTetherDisablePreferenceControllerTest { when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn( mConnectivityManager); when(mConnectivityManager.getTetherableWifiRegexs()).thenReturn(new String[]{""}); - when(mContext.getSharedPreferences(TetherEnabler.SHARED_PREF, Context.MODE_PRIVATE)) - .thenReturn(mSharedPreferences); mController = new WifiTetherDisablePreferenceController(mContext, WIFI_TETHER_DISABLE_KEY); + mController.setTetherEnabler(mTetherEnabler); ReflectionHelpers.setField(mController, "mScreen", mPreferenceScreen); ReflectionHelpers.setField(mController, "mPreference", mPreference); when(mPreferenceScreen.findPreference(WIFI_TETHER_DISABLE_KEY)).thenReturn(mPreference); } - @Test - - public void lifecycle_shouldRegisterReceiverOnResume() { - mController.onResume(); - - verify(mSharedPreferences).registerOnSharedPreferenceChangeListener(eq(mController)); - } - - @Test - public void lifecycle_shouldUnregisterReceiverOnStop() { - mController.onResume(); - mController.onPause(); - - verify(mSharedPreferences).unregisterOnSharedPreferenceChangeListener(eq(mController)); - } - @Test public void display_availableChangedCorrectly() { when(mConnectivityManager.getTetherableWifiRegexs()).thenReturn(new String[0]); assertThat(mController.isAvailable()).isFalse(); when(mConnectivityManager.getTetherableWifiRegexs()).thenReturn(new String[]{"test"}); - ReflectionHelpers.setField(mController, "mBluetoothTetherEnabled", false); - ReflectionHelpers.setField(mController, "mUSBTetherEnabled", false); + ReflectionHelpers.setField(mController, "mBluetoothTethering", false); + ReflectionHelpers.setField(mController, "mUsbTethering", false); assertThat(mController.isAvailable()).isFalse(); } @Test public void switch_shouldListenToUsbAndBluetooth() { - when(mSharedPreferences.getBoolean(BLUETOOTH_TETHER_KEY, false)).thenReturn(true); - mController.onSharedPreferenceChanged(mSharedPreferences, BLUETOOTH_TETHER_KEY); + int state = TetherEnabler.TETHERING_BLUETOOTH_ON; + mController.onTetherStateUpdated(state); verify(mPreference).setVisible(eq(true)); - when(mSharedPreferences.getBoolean(USB_TETHER_KEY, false)).thenReturn(true); - mController.onSharedPreferenceChanged(mSharedPreferences, USB_TETHER_KEY); + state |= TetherEnabler.TETHERING_USB_ON; + mController.onTetherStateUpdated(state); assertThat(mController.shouldShow()).isTrue(); - when(mSharedPreferences.getBoolean(USB_TETHER_KEY, false)).thenReturn(false); - mController.onSharedPreferenceChanged(mSharedPreferences, USB_TETHER_KEY); + state = TetherEnabler.TETHERING_USB_ON; + mController.onTetherStateUpdated(state); assertThat(mController.shouldShow()).isTrue(); - when(mSharedPreferences.getBoolean(BLUETOOTH_TETHER_KEY, false)).thenReturn(false); - when(mSharedPreferences.edit()).thenReturn(mock(SharedPreferences.Editor.class)); - when(mPreference.isChecked()).thenReturn(true); - mController.onSharedPreferenceChanged(mSharedPreferences, BLUETOOTH_TETHER_KEY); - verify(mPreference).setChecked(eq(false)); + state = TetherEnabler.TETHERING_OFF; + mController.onTetherStateUpdated(state); verify(mPreference).setVisible(eq(false)); } } From 3b53b807154a0bd3d1dccb44ad733838daf74ad0 Mon Sep 17 00:00:00 2001 From: Zhen Zhang Date: Mon, 23 Mar 2020 12:18:14 -0700 Subject: [PATCH 2/2] Fix crash in AllInOneTetherSettings when user is not admin When user is not admin, we should skip the setup and tear down procedures in AllInOneTetherSettings' lifecycle. Also, the switch for "Hotspot & tethering" on "Network & internet" should be disabled in such case. Bug: 151648198 Test: Build and flashed to crosshatch device. Using guest user, the settings won't crash when using AllInOneTetherSetting and the switch is disabled. Change-Id: Ibd2f4111c53b8b9fa6a18504a681a27b966a3c46 --- .../settings/AllInOneTetherSettings.java | 17 +++++++++++++++-- .../android/settings/network/TetherEnabler.java | 16 ++++++++++++---- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/com/android/settings/AllInOneTetherSettings.java b/src/com/android/settings/AllInOneTetherSettings.java index 69edf4348b6..c562faee1d7 100644 --- a/src/com/android/settings/AllInOneTetherSettings.java +++ b/src/com/android/settings/AllInOneTetherSettings.java @@ -249,18 +249,31 @@ public class AllInOneTetherSettings extends RestrictedDashboardFragment @Override public void onResume() { super.onResume(); - mTetherEnabler.addListener(mStateUpdateListener); + if (mUnavailable) { + return; + } + if (mTetherEnabler != null) { + mTetherEnabler.addListener(mStateUpdateListener); + } } @Override public void onPause() { super.onPause(); - mTetherEnabler.removeListener(mStateUpdateListener); + if (mUnavailable) { + return; + } + if (mTetherEnabler != null) { + mTetherEnabler.removeListener(mStateUpdateListener); + } } @Override public void onStop() { super.onStop(); + if (mUnavailable) { + return; + } final Context context = getContext(); if (context != null) { context.unregisterReceiver(mTetherChangeReceiver); diff --git a/src/com/android/settings/network/TetherEnabler.java b/src/com/android/settings/network/TetherEnabler.java index 9cc9c5d67b6..c4b36d32c9d 100644 --- a/src/com/android/settings/network/TetherEnabler.java +++ b/src/com/android/settings/network/TetherEnabler.java @@ -35,6 +35,7 @@ import android.net.ConnectivityManager; import android.net.wifi.WifiManager; import android.os.Handler; import android.os.Looper; +import android.os.UserManager; import android.text.TextUtils; import android.util.Log; @@ -106,6 +107,7 @@ public class TetherEnabler implements SwitchWidgetController.OnSwitchChangeListe private final SwitchWidgetController mSwitchWidgetController; private final WifiManager mWifiManager; private final ConnectivityManager mConnectivityManager; + private final UserManager mUserManager; private final DataSaverBackend mDataSaverBackend; private boolean mDataSaverEnabled; @@ -128,6 +130,7 @@ public class TetherEnabler implements SwitchWidgetController.OnSwitchChangeListe mConnectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); + mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); mBluetoothPan = bluetoothPan; mDataSaverEnabled = mDataSaverBackend.isDataSaverEnabled(); @@ -171,6 +174,11 @@ public class TetherEnabler implements SwitchWidgetController.OnSwitchChangeListe } } + private void setSwitchEnabled(boolean enabled) { + mSwitchWidgetController.setEnabled( + enabled && !mDataSaverEnabled && mUserManager.isAdminUser()); + } + @VisibleForTesting void updateState(@Nullable String[] tethered) { int state = getTetheringState(tethered); @@ -178,7 +186,7 @@ public class TetherEnabler implements SwitchWidgetController.OnSwitchChangeListe Log.d(TAG, "updateState: " + state); } setSwitchCheckedInternal(state != TETHERING_OFF); - mSwitchWidgetController.setEnabled(!mDataSaverEnabled); + setSwitchEnabled(true); for (int i = 0, size = mListeners.size(); i < size; ++i) { mListeners.get(i).onTetherStateUpdated(state); } @@ -251,7 +259,7 @@ public class TetherEnabler implements SwitchWidgetController.OnSwitchChangeListe if ((choice == TETHERING_WIFI && isWifiTethering(state)) || (choice == TETHERING_USB && isUsbTethering(state)) || (choice == TETHERING_BLUETOOTH && isBluetoothTethering(state))) { - mSwitchWidgetController.setEnabled(false); + setSwitchEnabled(false); mConnectivityManager.stopTethering(choice); if (choice == TETHERING_BLUETOOTH) { // Stop bluetooth tether won't invoke tether state changed callback, so we need this @@ -283,7 +291,7 @@ public class TetherEnabler implements SwitchWidgetController.OnSwitchChangeListe } } - mSwitchWidgetController.setEnabled(false); + setSwitchEnabled(false); mConnectivityManager.startTethering(choice, true /* showProvisioningUi */, mOnStartTetheringCallback, new Handler(Looper.getMainLooper())); } @@ -351,7 +359,7 @@ public class TetherEnabler implements SwitchWidgetController.OnSwitchChangeListe @Override public void onDataSaverChanged(boolean isDataSaving) { mDataSaverEnabled = isDataSaving; - mSwitchWidgetController.setEnabled(!isDataSaving); + setSwitchEnabled(true); } @Override