diff --git a/src/com/android/settings/AllInOneTetherSettings.java b/src/com/android/settings/AllInOneTetherSettings.java index 251d1357b25..c562faee1d7 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,18 +249,31 @@ public class AllInOneTetherSettings extends RestrictedDashboardFragment @Override public void onResume() { super.onResume(); - mSharedPreferences.registerOnSharedPreferenceChangeListener(this); + if (mUnavailable) { + return; + } + if (mTetherEnabler != null) { + mTetherEnabler.addListener(mStateUpdateListener); + } } @Override public void onPause() { super.onPause(); - mSharedPreferences.unregisterOnSharedPreferenceChangeListener(this); + 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); @@ -365,13 +380,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 +390,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..c4b36d32c9d 100644 --- a/src/com/android/settings/network/TetherEnabler.java +++ b/src/com/android/settings/network/TetherEnabler.java @@ -31,11 +31,11 @@ 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; import android.os.Looper; +import android.os.UserManager; import android.text.TextUtils; import android.util.Log; @@ -51,21 +51,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 +72,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 +87,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 +102,23 @@ 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 UserManager mUserManager; 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 +127,14 @@ 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); + mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); mBluetoothPan = bluetoothPan; mDataSaverEnabled = mDataSaverBackend.isDataSaverEnabled(); + mListeners = new ArrayList<>(); } @OnLifecycleEvent(Lifecycle.Event.ON_START) @@ -148,38 +153,42 @@ 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); + } + } + + private void setSwitchEnabled(boolean enabled) { + mSwitchWidgetController.setEnabled( + enabled && !mDataSaverEnabled && mUserManager.isAdminUser()); } @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); - mSwitchWidgetController.setEnabled(!mDataSaverEnabled); - if (mListener != null) { - mListener.onTetherStateUpdated(tetherState != TETHERING_OFF); + setSwitchCheckedInternal(state != TETHERING_OFF); + setSwitchEnabled(true); + for (int i = 0, size = mListeners.size(); i < size; ++i) { + mListeners.get(i).onTetherStateUpdated(state); } } @@ -189,33 +198,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 +230,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))) { + setSwitchEnabled(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 +291,7 @@ public class TetherEnabler implements SwitchWidgetController.OnSwitchChangeListe } } + setSwitchEnabled(false); mConnectivityManager.startTethering(choice, true /* showProvisioningUi */, mOnStartTetheringCallback, new Handler(Looper.getMainLooper())); } @@ -379,7 +359,7 @@ public class TetherEnabler implements SwitchWidgetController.OnSwitchChangeListe @Override public void onDataSaverChanged(boolean isDataSaving) { mDataSaverEnabled = isDataSaving; - mSwitchWidgetController.setEnabled(!isDataSaving); + setSwitchEnabled(true); } @Override @@ -392,32 +372,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)); } }