diff --git a/res/values/strings.xml b/res/values/strings.xml index 0c878c47a5f..5ab9c33915b 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -3776,14 +3776,31 @@ USB only Bluetooth only + + Ethernet only Hotspot, USB Hotspot, Bluetooth + + Hotspot, Ethernet USB, Bluetooth + + USB, Ethernet + + Bluetooth, Ethernet Hotspot, USB, Bluetooth + + Hotspot, USB, Ethernet + + Hotspot, Bluetooth, Ethernet + + USB, Bluetooth, Ethernet + + Hotspot, USB, Bluetooth, Ethernet + Not sharing internet with other devices @@ -3797,8 +3814,16 @@ Only share internet via USB Only share internet via Bluetooth + + Only share internet via Ethernet Only share internet via USB and Bluetooth + + Only share internet via USB and Ethernet + + Only share internet via Bluetooth and Ethernet + + Only share internet via USB, Bluetooth and Ethernet USB diff --git a/res/xml/all_tether_prefs.xml b/res/xml/all_tether_prefs.xml index 294e9752312..84d5d2ac173 100644 --- a/res/xml/all_tether_prefs.xml +++ b/res/xml/all_tether_prefs.xml @@ -71,6 +71,13 @@ settings:controller="com.android.settings.network.BluetoothTetherPreferenceController" settings:keywords="@string/keywords_hotspot_tethering" /> + + { - mBluetoothTethering = TetherEnabler.isBluetoothTethering(state); - mUsbTethering = TetherEnabler.isUsbTethering(state); - mWifiTethering = TetherEnabler.isWifiTethering(state); - mWifiTetherGroup.setVisible(shouldShowWifiConfig()); + mShouldShowWifiConfig = TetherEnabler.isTethering(state, TETHERING_WIFI) + || state == TetherEnabler.TETHERING_OFF; + getPreferenceScreen().setInitialExpandedChildrenCount( + getInitialExpandedChildCount()); + mWifiTetherGroup.setVisible(mShouldShowWifiConfig); }; private final BroadcastReceiver mTetherChangeReceiver = new BroadcastReceiver() { @@ -182,13 +189,13 @@ public class AllInOneTetherSettings extends RestrictedDashboardFragment mApBandPreferenceController = use(WifiTetherApBandPreferenceController.class); getSettingsLifecycle().addObserver(use(UsbTetherPreferenceController.class)); getSettingsLifecycle().addObserver(use(BluetoothTetherPreferenceController.class)); + getSettingsLifecycle().addObserver(use(EthernetTetherPreferenceController.class)); getSettingsLifecycle().addObserver(use(WifiTetherDisablePreferenceController.class)); } @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); - mDataSaverBackend = new DataSaverBackend(getContext()); mDataSaverEnabled = mDataSaverBackend.isDataSaverEnabled(); mDataSaverFooter = findPreference(KEY_DATA_SAVER_FOOTER); @@ -226,6 +233,7 @@ public class AllInOneTetherSettings extends RestrictedDashboardFragment getSettingsLifecycle().addObserver(mTetherEnabler); use(UsbTetherPreferenceController.class).setTetherEnabler(mTetherEnabler); use(BluetoothTetherPreferenceController.class).setTetherEnabler(mTetherEnabler); + use(EthernetTetherPreferenceController.class).setTetherEnabler(mTetherEnabler); use(WifiTetherDisablePreferenceController.class).setTetherEnabler(mTetherEnabler); switchBar.show(); } @@ -379,14 +387,11 @@ public class AllInOneTetherSettings extends RestrictedDashboardFragment mApBandPreferenceController.updateDisplay(); } - private boolean shouldShowWifiConfig() { - return mWifiTethering || (!mBluetoothTethering && !mUsbTethering); - } - @Override public int getInitialExpandedChildCount() { - if (!shouldShowWifiConfig()) { - return EXPANDED_CHILD_COUNT_WITHOUT_WIFI_CONFIG; + if (mHasShownAdvance || !mShouldShowWifiConfig) { + mHasShownAdvance = true; + return EXPANDED_CHILD_COUNT_MAX; } if (mSecurityPreferenceController == null) { @@ -398,6 +403,12 @@ public class AllInOneTetherSettings extends RestrictedDashboardFragment ? EXPANDED_CHILD_COUNT_WITH_SECURITY_NON : EXPANDED_CHILD_COUNT_DEFAULT; } + @Override + public void onExpandButtonClick() { + super.onExpandButtonClick(); + mHasShownAdvance = true; + } + public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = new BaseSearchIndexProvider(R.xml.all_tether_prefs) { diff --git a/src/com/android/settings/network/AllInOneTetherPreferenceController.java b/src/com/android/settings/network/AllInOneTetherPreferenceController.java index 50c3a6439ed..595e31bab09 100644 --- a/src/com/android/settings/network/AllInOneTetherPreferenceController.java +++ b/src/com/android/settings/network/AllInOneTetherPreferenceController.java @@ -17,6 +17,11 @@ package com.android.settings.network; import static android.os.UserManager.DISALLOW_CONFIG_TETHERING; +import static com.android.settings.network.TetherEnabler.TETHERING_BLUETOOTH_ON; +import static com.android.settings.network.TetherEnabler.TETHERING_ETHERNET_ON; +import static com.android.settings.network.TetherEnabler.TETHERING_OFF; +import static com.android.settings.network.TetherEnabler.TETHERING_USB_ON; +import static com.android.settings.network.TetherEnabler.TETHERING_WIFI_ON; import static com.android.settingslib.RestrictedLockUtilsInternal.checkIfRestrictionEnforced; import android.bluetooth.BluetoothAdapter; @@ -52,19 +57,7 @@ public class AllInOneTetherPreferenceController extends BasePreferenceController LifecycleObserver, TetherEnabler.OnTetherStateUpdateListener { private static final String TAG = "AllInOneTetherPreferenceController"; - 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 int mTetheringState; private final boolean mAdminDisallowedTetherConfig; private final AtomicReference mBluetoothPan; @@ -124,32 +117,49 @@ public class AllInOneTetherPreferenceController extends BasePreferenceController @Override public CharSequence getSummary() { - if (mPreference != null && mPreference.isChecked()) { - switch (mTetheringType) { - case TETHERING_TYPE_HOTSPOT_ONLY: - return mContext.getString(R.string.tether_settings_summary_hotspot_only); - case TETHERING_TYPE_USB_ONLY: - return mContext.getString(R.string.tether_settings_summary_usb_tethering_only); - case TETHERING_TYPE_BLUETOOTH_ONLY: - return mContext.getString( - R.string.tether_settings_summary_bluetooth_tethering_only); - case TETHERING_TYPE_HOTSPOT_AND_USB: - return mContext.getString(R.string.tether_settings_summary_hotspot_and_usb); - case TETHERING_TYPE_HOTSPOT_AND_BLUETOOTH: - return mContext.getString( - R.string.tether_settings_summary_hotspot_and_bluetooth); - case TETHERING_TYPE_USB_AND_BLUETOOTH: - return mContext.getString(R.string.tether_settings_summary_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: - Log.e(TAG, "None of the tether interfaces is chosen"); - return mContext.getString(R.string.summary_placeholder); - } + switch (mTetheringState) { + case TETHERING_OFF: + return mContext.getString(R.string.tether_settings_summary_off); + case TETHERING_WIFI_ON: + return mContext.getString(R.string.tether_settings_summary_hotspot_only); + case TETHERING_USB_ON: + return mContext.getString(R.string.tether_settings_summary_usb_tethering_only); + case TETHERING_BLUETOOTH_ON: + return mContext.getString( + R.string.tether_settings_summary_bluetooth_tethering_only); + case TETHERING_ETHERNET_ON: + return mContext.getString(R.string.tether_settings_summary_ethernet_tethering_only); + case TETHERING_WIFI_ON | TETHERING_USB_ON: + return mContext.getString(R.string.tether_settings_summary_hotspot_and_usb); + case TETHERING_WIFI_ON | TETHERING_BLUETOOTH_ON: + return mContext.getString(R.string.tether_settings_summary_hotspot_and_bluetooth); + case TETHERING_WIFI_ON | TETHERING_ETHERNET_ON: + return mContext.getString(R.string.tether_settings_summary_hotspot_and_ethernet); + case TETHERING_USB_ON | TETHERING_BLUETOOTH_ON: + return mContext.getString(R.string.tether_settings_summary_usb_and_bluetooth); + case TETHERING_USB_ON | TETHERING_ETHERNET_ON: + return mContext.getString(R.string.tether_settings_summary_usb_and_ethernet); + case TETHERING_BLUETOOTH_ON | TETHERING_ETHERNET_ON: + return mContext.getString(R.string.tether_settings_summary_bluetooth_and_ethernet); + case TETHERING_WIFI_ON | TETHERING_USB_ON | TETHERING_BLUETOOTH_ON: + return mContext.getString( + R.string.tether_settings_summary_hotspot_and_usb_and_bluetooth); + case TETHERING_WIFI_ON | TETHERING_USB_ON | TETHERING_ETHERNET_ON: + return mContext.getString( + R.string.tether_settings_summary_hotspot_and_usb_and_ethernet); + case TETHERING_WIFI_ON | TETHERING_BLUETOOTH_ON | TETHERING_ETHERNET_ON: + return mContext.getString( + R.string.tether_settings_summary_hotspot_and_bluetooth_and_ethernet); + case TETHERING_USB_ON | TETHERING_BLUETOOTH_ON | TETHERING_ETHERNET_ON: + return mContext.getString( + R.string.tether_settings_summary_usb_and_bluetooth_and_ethernet); + case TETHERING_WIFI_ON | TETHERING_USB_ON | TETHERING_BLUETOOTH_ON + | TETHERING_ETHERNET_ON: + return mContext.getString(R.string.tether_settings_summary_all); + default: + Log.e(TAG, "Unknown tethering state"); + return mContext.getString(R.string.summary_placeholder); } - - return mContext.getString(R.string.tether_settings_summary_off); } @OnLifecycleEvent(Event.ON_CREATE) @@ -197,11 +207,7 @@ public class AllInOneTetherPreferenceController extends BasePreferenceController @Override 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; + mTetheringState = state; updateState(mPreference); } } diff --git a/src/com/android/settings/network/BluetoothTetherPreferenceController.java b/src/com/android/settings/network/BluetoothTetherPreferenceController.java index dc66254e126..ab507da2f9e 100644 --- a/src/com/android/settings/network/BluetoothTetherPreferenceController.java +++ b/src/com/android/settings/network/BluetoothTetherPreferenceController.java @@ -21,51 +21,25 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.net.TetheringManager; +import android.net.ConnectivityManager; import android.text.TextUtils; -import android.util.Log; import androidx.lifecycle.Lifecycle; -import androidx.lifecycle.LifecycleObserver; import androidx.lifecycle.OnLifecycleEvent; -import androidx.preference.Preference; 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. + * preference. */ -public final class BluetoothTetherPreferenceController extends TetherBasePreferenceController - implements LifecycleObserver { - - private static final String TAG = "BluetoothTetherPreferenceController"; - private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); +public final class BluetoothTetherPreferenceController extends TetherBasePreferenceController { private int mBluetoothState; - private boolean mBluetoothTethering; public BluetoothTetherPreferenceController(Context context, String preferenceKey) { super(context, preferenceKey); } - @Override - public boolean isChecked() { - return mBluetoothTethering; - } - - @Override - public boolean setChecked(boolean isChecked) { - if (mTetherEnabler == null) { - return false; - } - if (isChecked) { - mTetherEnabler.startTethering(TetheringManager.TETHERING_BLUETOOTH); - } else { - mTetherEnabler.stopTethering(TetheringManager.TETHERING_BLUETOOTH); - } - return true; - } - @OnLifecycleEvent(Lifecycle.Event.ON_START) public void onStart() { mBluetoothState = BluetoothAdapter.getDefaultAdapter().getState(); @@ -79,41 +53,30 @@ public final class BluetoothTetherPreferenceController extends TetherBasePrefere } @Override - public void updateState(Preference preference) { - super.updateState(preference); - if (preference == null) { - return; - } - + public boolean shouldEnable() { switch (mBluetoothState) { case BluetoothAdapter.STATE_ON: case BluetoothAdapter.STATE_OFF: // fall through. case BluetoothAdapter.ERROR: - preference.setEnabled(true); - break; + return true; case BluetoothAdapter.STATE_TURNING_OFF: case BluetoothAdapter.STATE_TURNING_ON: // fall through. default: - preference.setEnabled(false); + return false; } } @Override - public int getAvailabilityStatus() { + public boolean shouldShow() { final String[] bluetoothRegexs = mCm.getTetherableBluetoothRegexs(); - if (bluetoothRegexs == null || bluetoothRegexs.length == 0) { - return CONDITIONALLY_UNAVAILABLE; - } else { - return AVAILABLE; - } + return bluetoothRegexs != null && bluetoothRegexs.length != 0; } @Override - public void onTetherStateUpdated(int state) { - mBluetoothTethering = TetherEnabler.isBluetoothTethering(state); - updateState(mPreference); + public int getTetherType() { + return ConnectivityManager.TETHERING_BLUETOOTH; } @VisibleForTesting diff --git a/src/com/android/settings/network/EthernetTetherPreferenceController.java b/src/com/android/settings/network/EthernetTetherPreferenceController.java new file mode 100644 index 00000000000..19c410d8672 --- /dev/null +++ b/src/com/android/settings/network/EthernetTetherPreferenceController.java @@ -0,0 +1,86 @@ +/* + * 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.EthernetManager; +import android.net.TetheringManager; +import android.os.Handler; +import android.os.Looper; +import android.text.TextUtils; + +import androidx.lifecycle.Lifecycle; +import androidx.lifecycle.OnLifecycleEvent; + +import com.android.internal.annotations.VisibleForTesting; + +/** + * This controller helps to manage the switch state and visibility of ethernet tether switch + * preference. + */ +public final class EthernetTetherPreferenceController extends TetherBasePreferenceController { + + private final String mEthernetRegex; + private final EthernetManager mEthernetManager; + @VisibleForTesting + EthernetManager.Listener mEthernetListener; + + public EthernetTetherPreferenceController(Context context, String preferenceKey) { + super(context, preferenceKey); + mEthernetRegex = context.getString( + com.android.internal.R.string.config_ethernet_iface_regex); + mEthernetManager = (EthernetManager) context.getSystemService(Context.ETHERNET_SERVICE); + } + + @OnLifecycleEvent(Lifecycle.Event.ON_START) + public void onStart() { + mEthernetListener = new EthernetManager.Listener() { + @Override + public void onAvailabilityChanged(String iface, boolean isAvailable) { + new Handler(Looper.getMainLooper()).post(() -> updateState(mPreference)); + } + }; + mEthernetManager.addListener(mEthernetListener); + } + + @OnLifecycleEvent(Lifecycle.Event.ON_STOP) + public void onStop() { + mEthernetManager.removeListener(mEthernetListener); + mEthernetListener = null; + } + + @Override + public boolean shouldEnable() { + String[] available = mCm.getTetherableIfaces(); + for (String s : available) { + if (s.matches(mEthernetRegex)) { + return true; + } + } + return false; + } + + @Override + public boolean shouldShow() { + return !TextUtils.isEmpty(mEthernetRegex); + } + + @Override + public int getTetherType() { + return TetheringManager.TETHERING_ETHERNET; + } +} diff --git a/src/com/android/settings/network/TetherBasePreferenceController.java b/src/com/android/settings/network/TetherBasePreferenceController.java index 71bf1166b2b..36ce2a47c93 100644 --- a/src/com/android/settings/network/TetherBasePreferenceController.java +++ b/src/com/android/settings/network/TetherBasePreferenceController.java @@ -18,7 +18,6 @@ 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; @@ -27,20 +26,26 @@ import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import com.android.settings.core.TogglePreferenceController; +import com.android.settings.datausage.DataSaverBackend; public abstract class TetherBasePreferenceController extends TogglePreferenceController - implements LifecycleObserver, TetherEnabler.OnTetherStateUpdateListener { + implements LifecycleObserver, DataSaverBackend.Listener, + TetherEnabler.OnTetherStateUpdateListener { private static final String TAG = "TetherBasePreferenceController"; - static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); final ConnectivityManager mCm; + private final DataSaverBackend mDataSaverBackend; - TetherEnabler mTetherEnabler; + private TetherEnabler mTetherEnabler; Preference mPreference; + private boolean mDataSaverEnabled; + int mTetheringState; - public TetherBasePreferenceController(Context context, String preferenceKey) { + TetherBasePreferenceController(Context context, String preferenceKey) { super(context, preferenceKey); mCm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + mDataSaverBackend = new DataSaverBackend(context); + mDataSaverEnabled = mDataSaverBackend.isDataSaverEnabled(); } /** @@ -57,6 +62,7 @@ public abstract class TetherBasePreferenceController extends TogglePreferenceCon if (mTetherEnabler != null) { mTetherEnabler.addListener(this); } + mDataSaverBackend.addListener(this); } @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE) @@ -64,6 +70,25 @@ public abstract class TetherBasePreferenceController extends TogglePreferenceCon if (mTetherEnabler != null) { mTetherEnabler.removeListener(this); } + mDataSaverBackend.remListener(this); + } + + @Override + public boolean isChecked() { + return TetherEnabler.isTethering(mTetheringState, getTetherType()); + } + + @Override + public boolean setChecked(boolean isChecked) { + if (mTetherEnabler == null) { + return false; + } + if (isChecked) { + mTetherEnabler.startTethering(getTetherType()); + } else { + mTetherEnabler.stopTethering(getTetherType()); + } + return true; } @Override @@ -71,4 +96,61 @@ public abstract class TetherBasePreferenceController extends TogglePreferenceCon super.displayPreference(screen); mPreference = screen.findPreference(mPreferenceKey); } + + @Override + public void updateState(Preference preference) { + super.updateState(preference); + if (isAvailable()) { + preference.setEnabled(getAvailabilityStatus() != DISABLED_DEPENDENT_SETTING); + } + } + + @Override + public int getAvailabilityStatus() { + if (!shouldShow()) { + return CONDITIONALLY_UNAVAILABLE; + } + + if (mDataSaverEnabled || !shouldEnable()) { + return DISABLED_DEPENDENT_SETTING; + } + return AVAILABLE; + } + + @Override + public void onTetherStateUpdated(@TetherEnabler.TetheringState int state) { + mTetheringState = state; + updateState(mPreference); + } + + @Override + public void onDataSaverChanged(boolean isDataSaving) { + mDataSaverEnabled = isDataSaving; + } + + @Override + public void onWhitelistStatusChanged(int uid, boolean isWhitelisted) { + } + + @Override + public void onBlacklistStatusChanged(int uid, boolean isBlacklisted) { + } + + /** + * Used to enable or disable the preference. + * @return true if the preference should be enabled; false otherwise. + */ + public abstract boolean shouldEnable(); + + /** + * Used to determine visibility of the preference. + * @return true if the preference should be visible; false otherwise. + */ + public abstract boolean shouldShow(); + + /** + * Get the type of tether interface that is controlled by the preference. + * @return the tether interface, like {@link ConnectivityManager#TETHERING_WIFI} + */ + public abstract int getTetherType(); } diff --git a/src/com/android/settings/network/TetherEnabler.java b/src/com/android/settings/network/TetherEnabler.java index 87832d99817..b3c6d615002 100644 --- a/src/com/android/settings/network/TetherEnabler.java +++ b/src/com/android/settings/network/TetherEnabler.java @@ -19,8 +19,7 @@ package com.android.settings.network; import static android.net.ConnectivityManager.TETHERING_BLUETOOTH; import static android.net.ConnectivityManager.TETHERING_USB; import static android.net.ConnectivityManager.TETHERING_WIFI; - -import static com.android.settings.AllInOneTetherSettings.DEDUP_POSTFIX; +import static android.net.TetheringManager.TETHERING_ETHERNET; import static java.lang.annotation.RetentionPolicy.SOURCE; @@ -32,8 +31,10 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.net.ConnectivityManager; +import android.net.TetheringManager; import android.net.wifi.WifiManager; import android.os.Handler; +import android.os.HandlerExecutor; import android.os.Looper; import android.os.UserManager; import android.text.TextUtils; @@ -84,38 +85,37 @@ public class TetherEnabler implements SwitchWidgetController.OnSwitchChangeListe @Retention(SOURCE) @IntDef( flag = true, - value = {TETHERING_OFF, TETHERING_WIFI_ON, TETHERING_USB_ON, TETHERING_BLUETOOTH_ON} + value = { + TETHERING_OFF, + TETHERING_WIFI_ON, + TETHERING_USB_ON, + TETHERING_BLUETOOTH_ON, + TETHERING_ETHERNET_ON + } ) @interface TetheringState {} - @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"; - public static final String WIFI_TETHER_DISABLE_KEY = "disable_wifi_tethering"; - public static final String USB_TETHER_KEY = "enable_usb_tethering"; - public static final String BLUETOOTH_TETHER_KEY = "enable_bluetooth_tethering" + DEDUP_POSTFIX; + public static final int TETHERING_OFF = 0; + public static final int TETHERING_WIFI_ON = 1 << TETHERING_WIFI; + public static final int TETHERING_USB_ON = 1 << TETHERING_USB; + public static final int TETHERING_BLUETOOTH_ON = 1 << TETHERING_BLUETOOTH; + public static final int TETHERING_ETHERNET_ON = 1 << TETHERING_ETHERNET; @VisibleForTesting final List mListeners; + private final Handler mMainThreadHandler; private final SwitchWidgetController mSwitchWidgetController; private final WifiManager mWifiManager; private final ConnectivityManager mConnectivityManager; + private final TetheringManager mTetheringManager; private final UserManager mUserManager; - + private final String mEthernetRegex; private final DataSaverBackend mDataSaverBackend; private boolean mDataSaverEnabled; @VisibleForTesting boolean mBluetoothTetheringStoppedByUser; - private final Context mContext; - + @VisibleForTesting + TetheringManager.TetheringEventCallback mTetheringEventCallback; @VisibleForTesting ConnectivityManager.OnStartTetheringCallback mOnStartTetheringCallback; private final AtomicReference mBluetoothPan; @@ -129,12 +129,16 @@ public class TetherEnabler implements SwitchWidgetController.OnSwitchChangeListe mDataSaverBackend = new DataSaverBackend(context); mConnectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + mTetheringManager = (TetheringManager) context.getSystemService(Context.TETHERING_SERVICE); mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); mBluetoothPan = bluetoothPan; + mEthernetRegex = + context.getString(com.android.internal.R.string.config_ethernet_iface_regex); mDataSaverEnabled = mDataSaverBackend.isDataSaverEnabled(); mListeners = new ArrayList<>(); + mMainThreadHandler = new Handler(Looper.getMainLooper()); } @OnLifecycleEvent(Lifecycle.Event.ON_START) @@ -142,12 +146,20 @@ public class TetherEnabler implements SwitchWidgetController.OnSwitchChangeListe mDataSaverBackend.addListener(this); mSwitchWidgetController.setListener(this); mSwitchWidgetController.startListening(); - final IntentFilter filter = new IntentFilter( ConnectivityManager.ACTION_TETHER_STATE_CHANGED); filter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION); filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); mContext.registerReceiver(mTetherChangeReceiver, filter); + mTetheringEventCallback = + new TetheringManager.TetheringEventCallback() { + @Override + public void onTetheredInterfacesChanged(List interfaces) { + updateState(interfaces.toArray(new String[interfaces.size()])); + } + }; + mTetheringManager.registerTetheringEventCallback(new HandlerExecutor(mMainThreadHandler), + mTetheringEventCallback); mOnStartTetheringCallback = new OnStartTetheringCallback(this); updateState(null/*tethered*/); @@ -159,6 +171,8 @@ public class TetherEnabler implements SwitchWidgetController.OnSwitchChangeListe mDataSaverBackend.remListener(this); mSwitchWidgetController.stopListening(); mContext.unregisterReceiver(mTetherChangeReceiver); + mTetheringManager.unregisterTetheringEventCallback(mTetheringEventCallback); + mTetheringEventCallback = null; } public void addListener(OnTetherStateUpdateListener listener) { @@ -193,13 +207,19 @@ public class TetherEnabler implements SwitchWidgetController.OnSwitchChangeListe } private void setSwitchCheckedInternal(boolean checked) { - mSwitchWidgetController.stopListening(); + try { + mSwitchWidgetController.stopListening(); + } catch (IllegalStateException e) { + Log.e(TAG, "failed to stop switch widget listener when set check internally"); + return; + } mSwitchWidgetController.setChecked(checked); mSwitchWidgetController.startListening(); } @VisibleForTesting - @TetheringState int getTetheringState(@Nullable String[] tethered) { + @TetheringState + int getTetheringState(@Nullable String[] tethered) { int tetherState = TETHERING_OFF; if (tethered == null) { tethered = mConnectivityManager.getTetheredIfaces(); @@ -223,24 +243,19 @@ public class TetherEnabler implements SwitchWidgetController.OnSwitchChangeListe for (String s : tethered) { for (String regex : usbRegexs) { if (s.matches(regex)) { - return tetherState | TETHERING_USB_ON; + tetherState |= TETHERING_USB_ON; } } + if (s.matches(mEthernetRegex)) { + tetherState |= TETHERING_ETHERNET_ON; + } } 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; + public static boolean isTethering(@TetheringState int state, int choice) { + return (state & (1 << choice)) != TETHERING_OFF; } @Override @@ -251,15 +266,14 @@ public class TetherEnabler implements SwitchWidgetController.OnSwitchChangeListe stopTethering(TETHERING_USB); stopTethering(TETHERING_WIFI); stopTethering(TETHERING_BLUETOOTH); + stopTethering(TETHERING_ETHERNET); } return true; } public void stopTethering(int choice) { int state = getTetheringState(null /* tethered */); - if ((choice == TETHERING_WIFI && isWifiTethering(state)) - || (choice == TETHERING_USB && isUsbTethering(state)) - || (choice == TETHERING_BLUETOOTH && isBluetoothTethering(state))) { + if (isTethering(state, choice)) { setSwitchEnabled(false); mConnectivityManager.stopTethering(choice); if (choice == TETHERING_BLUETOOTH) { @@ -272,41 +286,35 @@ public class TetherEnabler implements SwitchWidgetController.OnSwitchChangeListe } public void startTethering(int choice) { + if (choice == TETHERING_BLUETOOTH) { + mBluetoothTetheringStoppedByUser = false; + } int state = getTetheringState(null /* tethered */); - if ((choice == TETHERING_WIFI && isWifiTethering(state)) - || (choice == TETHERING_USB && isUsbTethering(state))) { + if (isTethering(state, choice)) { return; } - if (choice == TETHERING_BLUETOOTH) { - mBluetoothTetheringStoppedByUser = false; - if (mBluetoothAdapter == null || isBluetoothTethering(state)) { - return; - } else if (mBluetoothAdapter.getState() == BluetoothAdapter.STATE_OFF) { - if (DEBUG) { - Log.d(TAG, "Turn on bluetooth first."); - } - mBluetoothEnableForTether = true; - mBluetoothAdapter.enable(); - return; + if (choice == TETHERING_BLUETOOTH && mBluetoothAdapter != null + && mBluetoothAdapter.getState() == BluetoothAdapter.STATE_OFF) { + if (DEBUG) { + Log.d(TAG, "Turn on bluetooth first."); } + mBluetoothEnableForTether = true; + mBluetoothAdapter.enable(); + return; } setSwitchEnabled(false); mConnectivityManager.startTethering(choice, true /* showProvisioningUi */, - mOnStartTetheringCallback, new Handler(Looper.getMainLooper())); + mOnStartTetheringCallback, mMainThreadHandler); } private final BroadcastReceiver mTetherChangeReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); - ArrayList active = null; boolean shouldUpdateState = false; - if (TextUtils.equals(ConnectivityManager.ACTION_TETHER_STATE_CHANGED, action)) { - active = intent.getStringArrayListExtra(ConnectivityManager.EXTRA_ACTIVE_TETHER); - shouldUpdateState = true; - } else if (TextUtils.equals(WifiManager.WIFI_AP_STATE_CHANGED_ACTION, action)) { + if (TextUtils.equals(WifiManager.WIFI_AP_STATE_CHANGED_ACTION, action)) { shouldUpdateState = handleWifiApStateChanged(intent.getIntExtra( WifiManager.EXTRA_WIFI_AP_STATE, WifiManager.WIFI_AP_STATE_FAILED)); } else if (TextUtils.equals(BluetoothAdapter.ACTION_STATE_CHANGED, action)) { @@ -315,11 +323,7 @@ public class TetherEnabler implements SwitchWidgetController.OnSwitchChangeListe } if (shouldUpdateState) { - if (active != null) { - updateState(active.toArray(new String[0])); - } else { - updateState(null/*tethered*/); - } + updateState(null /* tethered */); } } }; diff --git a/src/com/android/settings/network/UsbTetherPreferenceController.java b/src/com/android/settings/network/UsbTetherPreferenceController.java index a3a42936762..7cf1ddfcf98 100644 --- a/src/com/android/settings/network/UsbTetherPreferenceController.java +++ b/src/com/android/settings/network/UsbTetherPreferenceController.java @@ -21,54 +21,32 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.hardware.usb.UsbManager; -import android.net.TetheringManager; +import android.net.ConnectivityManager; import android.os.Environment; import android.text.TextUtils; import androidx.annotation.VisibleForTesting; import androidx.lifecycle.Lifecycle; -import androidx.lifecycle.LifecycleObserver; import androidx.lifecycle.OnLifecycleEvent; -import androidx.preference.Preference; import com.android.settings.Utils; /** * This controller helps to manage the switch state and visibility of USB tether switch - * preference. It stores preference values when preference changed. + * preference. * */ -public final class UsbTetherPreferenceController extends TetherBasePreferenceController implements - LifecycleObserver { +public final class UsbTetherPreferenceController extends TetherBasePreferenceController { private static final String TAG = "UsbTetherPrefController"; private boolean mUsbConnected; private boolean mMassStorageActive; - private boolean mUsbTethering; public UsbTetherPreferenceController(Context context, String prefKey) { super(context, prefKey); } - @Override - public boolean isChecked() { - return mUsbTethering; - } - - @Override - public boolean setChecked(boolean isChecked) { - if (mTetherEnabler == null) { - return false; - } - if (isChecked) { - mTetherEnabler.startTethering(TetheringManager.TETHERING_USB); - } else { - mTetherEnabler.stopTethering(TetheringManager.TETHERING_USB); - } - return true; - } - @OnLifecycleEvent(Lifecycle.Event.ON_START) public void onStart() { mMassStorageActive = Environment.MEDIA_SHARED.equals(Environment.getExternalStorageState()); @@ -84,27 +62,19 @@ public final class UsbTetherPreferenceController extends TetherBasePreferenceCon } @Override - public int getAvailabilityStatus() { + public boolean shouldEnable() { + return mUsbConnected && !mMassStorageActive; + } + + @Override + public boolean shouldShow() { String[] usbRegexs = mCm.getTetherableUsbRegexs(); - if (usbRegexs == null || usbRegexs.length == 0 || Utils.isMonkeyRunning()) { - return CONDITIONALLY_UNAVAILABLE; - } else { - return AVAILABLE; - } + return usbRegexs != null && usbRegexs.length != 0 && !Utils.isMonkeyRunning(); } @Override - public void updateState(Preference preference) { - super.updateState(preference); - if (preference != null) { - preference.setEnabled(mUsbConnected && !mMassStorageActive); - } - } - - @Override - public void onTetherStateUpdated(int state) { - mUsbTethering = TetherEnabler.isUsbTethering(state); - updateState(mPreference); + public int getTetherType() { + return ConnectivityManager.TETHERING_USB; } @VisibleForTesting diff --git a/src/com/android/settings/network/WifiTetherDisablePreferenceController.java b/src/com/android/settings/network/WifiTetherDisablePreferenceController.java index 544a886d12e..38e831bd38d 100644 --- a/src/com/android/settings/network/WifiTetherDisablePreferenceController.java +++ b/src/com/android/settings/network/WifiTetherDisablePreferenceController.java @@ -16,34 +16,31 @@ package com.android.settings.network; -import android.content.Context; -import android.net.TetheringManager; +import static com.android.settings.network.TetherEnabler.TETHERING_BLUETOOTH_ON; +import static com.android.settings.network.TetherEnabler.TETHERING_ETHERNET_ON; +import static com.android.settings.network.TetherEnabler.TETHERING_USB_ON; +import static com.android.settings.network.TetherEnabler.TETHERING_WIFI_ON; + +import android.content.Context; +import android.net.ConnectivityManager; -import androidx.lifecycle.LifecycleObserver; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; -import com.android.internal.annotations.VisibleForTesting; import com.android.settings.R; -import com.android.settingslib.TetherUtil; +import com.android.settings.Utils; /** * This controller helps to manage the switch state and visibility of wifi tether disable switch * preference. When the preference checked, wifi tether will be disabled. - * It stores preference value when preference changed and listens to usb tether and bluetooth tether - * preferences. * * @see BluetoothTetherPreferenceController * @see UsbTetherPreferenceController */ -public final class WifiTetherDisablePreferenceController extends TetherBasePreferenceController - implements LifecycleObserver { +public final class WifiTetherDisablePreferenceController extends TetherBasePreferenceController { private static final String TAG = "WifiTetherDisablePreferenceController"; - private boolean mBluetoothTethering; - private boolean mUsbTethering; - private boolean mWifiTethering; private PreferenceScreen mScreen; public WifiTetherDisablePreferenceController(Context context, String prefKey) { @@ -52,48 +49,57 @@ public final class WifiTetherDisablePreferenceController extends TetherBasePrefe @Override public boolean isChecked() { - return !mWifiTethering; + return !super.isChecked(); } @Override public boolean setChecked(boolean isChecked) { - if (mTetherEnabler == null) { - return false; - } - if (isChecked) { - mTetherEnabler.stopTethering(TetheringManager.TETHERING_WIFI); - } else { - mTetherEnabler.startTethering(TetheringManager.TETHERING_WIFI); - } - return true; + return super.setChecked(!isChecked); } - @VisibleForTesting - boolean shouldShow() { - return mBluetoothTethering || mUsbTethering; + private int getTetheringStateOfOtherInterfaces() { + return mTetheringState & (~TETHERING_WIFI_ON); } @Override - public int getAvailabilityStatus() { + public boolean shouldEnable() { + return true; + } + + @Override + public boolean shouldShow() { final String[] wifiRegexs = mCm.getTetherableWifiRegexs(); - if (wifiRegexs == null || wifiRegexs.length == 0 || !shouldShow() - || !TetherUtil.isTetherAvailable(mContext)) { - return CONDITIONALLY_UNAVAILABLE; - } else { - return AVAILABLE; - } + return wifiRegexs != null && wifiRegexs.length != 0 && !Utils.isMonkeyRunning() + && getTetheringStateOfOtherInterfaces() != TetherEnabler.TETHERING_OFF; + } + + @Override + public int getTetherType() { + return ConnectivityManager.TETHERING_WIFI; } @Override public CharSequence getSummary() { - if (mUsbTethering && mBluetoothTethering) { - return mContext.getString(R.string.disable_wifi_hotspot_when_usb_and_bluetooth_on); - } else if (mUsbTethering) { - return mContext.getString(R.string.disable_wifi_hotspot_when_usb_on); - } else if (mBluetoothTethering) { - return mContext.getString(R.string.disable_wifi_hotspot_when_bluetooth_on); + switch (getTetheringStateOfOtherInterfaces()) { + case TETHERING_USB_ON: + return mContext.getString(R.string.disable_wifi_hotspot_when_usb_on); + case TETHERING_BLUETOOTH_ON: + return mContext.getString(R.string.disable_wifi_hotspot_when_bluetooth_on); + case TETHERING_ETHERNET_ON: + return mContext.getString(R.string.disable_wifi_hotspot_when_ethernet_on); + case TETHERING_USB_ON | TETHERING_BLUETOOTH_ON: + return mContext.getString(R.string.disable_wifi_hotspot_when_usb_and_bluetooth_on); + case TETHERING_USB_ON | TETHERING_ETHERNET_ON: + return mContext.getString(R.string.disable_wifi_hotspot_when_usb_and_ethernet_on); + case TETHERING_BLUETOOTH_ON | TETHERING_ETHERNET_ON: + return mContext.getString( + R.string.disable_wifi_hotspot_when_bluetooth_and_ethernet_on); + case TETHERING_USB_ON | TETHERING_BLUETOOTH_ON | TETHERING_ETHERNET_ON: + return mContext.getString( + R.string.disable_wifi_hotspot_when_usb_and_bluetooth_and_ethernet_on); + default: + return mContext.getString(R.string.summary_placeholder); } - return mContext.getString(R.string.summary_placeholder); } @Override @@ -108,15 +114,7 @@ public final class WifiTetherDisablePreferenceController extends TetherBasePrefe @Override public void updateState(Preference preference) { super.updateState(preference); - setVisible(mScreen, mPreferenceKey, shouldShow()); + preference.setVisible(isAvailable()); refreshSummary(preference); } - - @Override - 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/AllInOneTetherSettingsTest.java b/tests/robotests/src/com/android/settings/AllInOneTetherSettingsTest.java index f966e3c5e75..c9a8c449d14 100644 --- a/tests/robotests/src/com/android/settings/AllInOneTetherSettingsTest.java +++ b/tests/robotests/src/com/android/settings/AllInOneTetherSettingsTest.java @@ -16,12 +16,13 @@ package com.android.settings; +import static com.android.settings.AllInOneTetherSettings.BLUETOOTH_TETHER_KEY; +import static com.android.settings.AllInOneTetherSettings.ETHERNET_TETHER_KEY; import static com.android.settings.AllInOneTetherSettings.EXPANDED_CHILD_COUNT_DEFAULT; -import static com.android.settings.AllInOneTetherSettings.EXPANDED_CHILD_COUNT_WITHOUT_WIFI_CONFIG; +import static com.android.settings.AllInOneTetherSettings.EXPANDED_CHILD_COUNT_MAX; import static com.android.settings.AllInOneTetherSettings.EXPANDED_CHILD_COUNT_WITH_SECURITY_NON; -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.android.settings.AllInOneTetherSettings.USB_TETHER_KEY; +import static com.android.settings.AllInOneTetherSettings.WIFI_TETHER_DISABLE_KEY; import static com.google.common.truth.Truth.assertThat; @@ -37,6 +38,9 @@ import android.os.UserHandle; import android.os.UserManager; import android.util.FeatureFlagUtils; +import androidx.preference.PreferenceGroup; +import androidx.preference.PreferenceScreen; + import com.android.settings.core.FeatureFlags; import com.android.settings.testutils.shadow.ShadowWifiManager; import com.android.settings.wifi.tether.WifiTetherAutoOffPreferenceController; @@ -62,6 +66,7 @@ public class AllInOneTetherSettingsTest { private static final String[] WIFI_REGEXS = {"wifi_regexs"}; private static final String[] USB_REGEXS = {"usb_regexs"}; private static final String[] BT_REGEXS = {"bt_regexs"}; + private static final String[] ETHERNET_REGEXS = {"ethernet_regexs"}; private Context mContext; private AllInOneTetherSettings mAllInOneTetherSettings; @@ -72,6 +77,10 @@ public class AllInOneTetherSettingsTest { private UserManager mUserManager; @Mock private WifiTetherSecurityPreferenceController mSecurityPreferenceController; + @Mock + private PreferenceScreen mPreferenceScreen; + @Mock + private PreferenceGroup mWifiTetherGroup; @Before public void setUp() { @@ -83,14 +92,16 @@ public class AllInOneTetherSettingsTest { doReturn(WIFI_REGEXS).when(mConnectivityManager).getTetherableWifiRegexs(); doReturn(USB_REGEXS).when(mConnectivityManager).getTetherableUsbRegexs(); doReturn(BT_REGEXS).when(mConnectivityManager).getTetherableBluetoothRegexs(); + doReturn(ETHERNET_REGEXS).when(mConnectivityManager).getTetherableIfaces(); doReturn(mUserManager).when(mContext).getSystemService(Context.USER_SERVICE); // Assume the feature is enabled for most test cases. FeatureFlagUtils.setEnabled(mContext, FeatureFlags.TETHER_ALL_IN_ONE, true); - - mAllInOneTetherSettings = new AllInOneTetherSettings(); + mAllInOneTetherSettings = spy(new AllInOneTetherSettings()); + doReturn(mPreferenceScreen).when(mAllInOneTetherSettings).getPreferenceScreen(); ReflectionHelpers.setField(mAllInOneTetherSettings, "mLifecycle", mock(Lifecycle.class)); ReflectionHelpers.setField(mAllInOneTetherSettings, "mSecurityPreferenceController", mSecurityPreferenceController); + ReflectionHelpers.setField(mAllInOneTetherSettings, "mWifiTetherGroup", mWifiTetherGroup); } @Test @@ -110,6 +121,7 @@ public class AllInOneTetherSettingsTest { assertThat(niks).doesNotContain(AllInOneTetherSettings.KEY_WIFI_TETHER_SECURITY); assertThat(niks).doesNotContain(BLUETOOTH_TETHER_KEY); assertThat(niks).doesNotContain(USB_TETHER_KEY); + assertThat(niks).doesNotContain(ETHERNET_TETHER_KEY); // This key should be returned because it's not visible by default. assertThat(niks).contains(WIFI_TETHER_DISABLE_KEY); @@ -131,6 +143,7 @@ public class AllInOneTetherSettingsTest { assertThat(niks).contains(WIFI_TETHER_DISABLE_KEY); assertThat(niks).contains(BLUETOOTH_TETHER_KEY); assertThat(niks).contains(USB_TETHER_KEY); + assertThat(niks).contains(ETHERNET_TETHER_KEY); } @Test @@ -149,6 +162,7 @@ public class AllInOneTetherSettingsTest { assertThat(niks).contains(WIFI_TETHER_DISABLE_KEY); assertThat(niks).doesNotContain(BLUETOOTH_TETHER_KEY); assertThat(niks).doesNotContain(USB_TETHER_KEY); + assertThat(niks).doesNotContain(ETHERNET_TETHER_KEY); } @Test @@ -167,29 +181,31 @@ public class AllInOneTetherSettingsTest { } @Test - public void getInitialExpandedChildCount_shouldShowWifiConfigWithSecurity() { - ReflectionHelpers.setField(mAllInOneTetherSettings, "mWifiTethering", true); + public void getInitialChildCount_withSecurity() { when(mSecurityPreferenceController.getSecurityType()) .thenReturn(SoftApConfiguration.SECURITY_TYPE_WPA2_PSK); - assertThat(mAllInOneTetherSettings.getInitialExpandedChildCount()) - .isEqualTo(EXPANDED_CHILD_COUNT_DEFAULT); + assertThat(mAllInOneTetherSettings.getInitialExpandedChildCount()).isEqualTo( + EXPANDED_CHILD_COUNT_DEFAULT); } @Test - public void getInitialExpandedChildCount_shouldShowWifiConfigWithoutSecurity() { - ReflectionHelpers.setField(mAllInOneTetherSettings, "mWifiTethering", true); + public void getInitialChildCount_withoutSecurity() { when(mSecurityPreferenceController.getSecurityType()) .thenReturn(SoftApConfiguration.SECURITY_TYPE_OPEN); - assertThat(mAllInOneTetherSettings.getInitialExpandedChildCount()) - .isEqualTo(EXPANDED_CHILD_COUNT_WITH_SECURITY_NON); + assertThat(mAllInOneTetherSettings.getInitialExpandedChildCount()).isEqualTo( + EXPANDED_CHILD_COUNT_WITH_SECURITY_NON); } @Test - public void getInitialExpandedChildCount_shouldNotShowWifiConfig() { - ReflectionHelpers.setField(mAllInOneTetherSettings, "mWifiTethering", false); - ReflectionHelpers.setField(mAllInOneTetherSettings, "mBluetoothTethering", true); + public void getInitialExpandedChildCount_expandAllChild() { assertThat(mAllInOneTetherSettings.getInitialExpandedChildCount()) - .isEqualTo(EXPANDED_CHILD_COUNT_WITHOUT_WIFI_CONFIG); + .isNotEqualTo(EXPANDED_CHILD_COUNT_MAX); + ReflectionHelpers.setField(mAllInOneTetherSettings, "mShouldShowWifiConfig", false); + assertThat(mAllInOneTetherSettings.getInitialExpandedChildCount()) + .isEqualTo(EXPANDED_CHILD_COUNT_MAX); + ReflectionHelpers.setField(mAllInOneTetherSettings, "mShouldShowWifiConfig", true); + assertThat(mAllInOneTetherSettings.getInitialExpandedChildCount()) + .isEqualTo(EXPANDED_CHILD_COUNT_MAX); } private void setupIsTetherAvailable(boolean returnValue) { diff --git a/tests/robotests/src/com/android/settings/network/AllInOneTetherPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/AllInOneTetherPreferenceControllerTest.java index 282a1709aac..12e687d8222 100644 --- a/tests/robotests/src/com/android/settings/network/AllInOneTetherPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/network/AllInOneTetherPreferenceControllerTest.java @@ -16,6 +16,14 @@ package com.android.settings.network; +import static com.android.settings.network.TetherEnabler.TETHERING_BLUETOOTH_ON; +import static com.android.settings.network.TetherEnabler.TETHERING_ETHERNET_ON; +import static com.android.settings.network.TetherEnabler.TETHERING_OFF; +import static com.android.settings.network.TetherEnabler.TETHERING_USB_ON; +import static com.android.settings.network.TetherEnabler.TETHERING_WIFI_ON; + +import static com.google.common.truth.Truth.assertThat; + import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; @@ -27,6 +35,7 @@ import android.bluetooth.BluetoothPan; import android.bluetooth.BluetoothProfile; import android.content.Context; +import com.android.settings.R; import com.android.settings.widget.MasterSwitchPreference; import org.junit.Before; @@ -34,14 +43,72 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.robolectric.RobolectricTestRunner; +import org.robolectric.ParameterizedRobolectricTestRunner; import org.robolectric.util.ReflectionHelpers; +import java.util.Arrays; +import java.util.List; import java.util.concurrent.atomic.AtomicReference; -@RunWith(RobolectricTestRunner.class) +@RunWith(ParameterizedRobolectricTestRunner.class) public class AllInOneTetherPreferenceControllerTest { + @ParameterizedRobolectricTestRunner.Parameters(name = "TetherState: {0}") + public static List params() { + return Arrays.asList(new Object[][] { + {TETHERING_OFF, R.string.tether_settings_summary_off}, + {TETHERING_WIFI_ON, R.string.tether_settings_summary_hotspot_only}, + {TETHERING_USB_ON, R.string.tether_settings_summary_usb_tethering_only}, + {TETHERING_BLUETOOTH_ON, R.string.tether_settings_summary_bluetooth_tethering_only}, + {TETHERING_ETHERNET_ON, R.string.tether_settings_summary_ethernet_tethering_only}, + { + TETHERING_WIFI_ON | TETHERING_USB_ON, + R.string.tether_settings_summary_hotspot_and_usb + }, + { + TETHERING_WIFI_ON | TETHERING_BLUETOOTH_ON, + R.string.tether_settings_summary_hotspot_and_bluetooth + }, + { + TETHERING_WIFI_ON | TETHERING_ETHERNET_ON, + R.string.tether_settings_summary_hotspot_and_ethernet + }, + { + TETHERING_USB_ON | TETHERING_BLUETOOTH_ON, + R.string.tether_settings_summary_usb_and_bluetooth + }, + { + TETHERING_USB_ON | TETHERING_ETHERNET_ON, + R.string.tether_settings_summary_usb_and_ethernet + }, + { + TETHERING_BLUETOOTH_ON | TETHERING_ETHERNET_ON, + R.string.tether_settings_summary_bluetooth_and_ethernet + }, + { + TETHERING_WIFI_ON | TETHERING_USB_ON | TETHERING_BLUETOOTH_ON, + R.string.tether_settings_summary_hotspot_and_usb_and_bluetooth + }, + { + TETHERING_WIFI_ON | TETHERING_USB_ON | TETHERING_ETHERNET_ON, + R.string.tether_settings_summary_hotspot_and_usb_and_ethernet + }, + { + TETHERING_WIFI_ON | TETHERING_BLUETOOTH_ON | TETHERING_ETHERNET_ON, + R.string.tether_settings_summary_hotspot_and_bluetooth_and_ethernet + }, + { + TETHERING_USB_ON | TETHERING_BLUETOOTH_ON | TETHERING_ETHERNET_ON, + R.string.tether_settings_summary_usb_and_bluetooth_and_ethernet + }, + { + TETHERING_WIFI_ON | TETHERING_USB_ON | TETHERING_BLUETOOTH_ON + | TETHERING_ETHERNET_ON, + R.string.tether_settings_summary_all + } + }); + } + @Mock private Context mContext; @Mock @@ -50,6 +117,13 @@ public class AllInOneTetherPreferenceControllerTest { private MasterSwitchPreference mPreference; private AllInOneTetherPreferenceController mController; + private final int mTetherState; + private final int mSummaryResId; + + public AllInOneTetherPreferenceControllerTest(int tetherState, int summaryResId) { + mTetherState = tetherState; + mSummaryResId = summaryResId; + } @Before public void setUp() { @@ -90,4 +164,10 @@ public class AllInOneTetherPreferenceControllerTest { verify(mBluetoothAdapter).closeProfileProxy(BluetoothProfile.PAN, pan); } + + @Test + public void getSummary_afterTetherStateChanged() { + mController.onTetherStateUpdated(mTetherState); + assertThat(mController.getSummary()).isEqualTo(mContext.getString(mSummaryResId)); + } } diff --git a/tests/robotests/src/com/android/settings/network/BluetoothTetherPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/BluetoothTetherPreferenceControllerTest.java index bab82ef250c..3b1f00818ec 100644 --- a/tests/robotests/src/com/android/settings/network/BluetoothTetherPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/network/BluetoothTetherPreferenceControllerTest.java @@ -16,8 +16,6 @@ package com.android.settings.network; -import static com.android.settings.network.TetherEnabler.BLUETOOTH_TETHER_KEY; - import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; @@ -26,6 +24,7 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.bluetooth.BluetoothAdapter; import android.content.Context; import android.net.ConnectivityManager; import android.net.TetheringManager; @@ -62,7 +61,7 @@ public class BluetoothTetherPreferenceControllerTest { when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn( mConnectivityManager); when(mConnectivityManager.getTetherableBluetoothRegexs()).thenReturn(new String[] {""}); - mController = new BluetoothTetherPreferenceController(mContext, BLUETOOTH_TETHER_KEY); + mController = new BluetoothTetherPreferenceController(mContext, "BLUETOOTH"); mController.setTetherEnabler(mTetherEnabler); ReflectionHelpers.setField(mController, "mPreference", mSwitchPreference); } @@ -98,14 +97,17 @@ public class BluetoothTetherPreferenceControllerTest { } @Test - public void display_availableChangedCorrectly() { - when(mConnectivityManager.getTetherableBluetoothRegexs()).thenReturn(new String[] {""}); - assertThat(mController.isAvailable()).isTrue(); - + public void shouldShow_noBluetoothTetherable() { when(mConnectivityManager.getTetherableBluetoothRegexs()).thenReturn(new String[0]); assertThat(mController.isAvailable()).isFalse(); } + @Test + public void shouldEnable_transientState() { + ReflectionHelpers.setField(mController, "mBluetoothState", + BluetoothAdapter.STATE_TURNING_OFF); + assertThat(mController.shouldEnable()).isFalse(); + } @Test public void setChecked_shouldStartBluetoothTethering() { mController.setChecked(true); diff --git a/tests/robotests/src/com/android/settings/network/EthernetTetherPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/EthernetTetherPreferenceControllerTest.java new file mode 100644 index 00000000000..d2e53b85ace --- /dev/null +++ b/tests/robotests/src/com/android/settings/network/EthernetTetherPreferenceControllerTest.java @@ -0,0 +1,141 @@ +/* + * 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 static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.EthernetManager; +import android.net.TetheringManager; + +import androidx.preference.SwitchPreference; +import androidx.test.core.app.ApplicationProvider; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.util.ReflectionHelpers; + +@RunWith(RobolectricTestRunner.class) +public class EthernetTetherPreferenceControllerTest { + + @Rule + public MockitoRule mocks = MockitoJUnit.rule(); + + @Mock + private ConnectivityManager mConnectivityManager; + @Mock + private EthernetManager mEthernetManager; + @Mock + private TetherEnabler mTetherEnabler; + + private Context mContext; + private EthernetTetherPreferenceController mController; + private SwitchPreference mPreference; + private static final String ETHERNET_REGEX = "ethernet"; + + @Before + public void setUp() { + mContext = spy(ApplicationProvider.getApplicationContext()); + mPreference = spy(SwitchPreference.class); + when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE)) + .thenReturn(mConnectivityManager); + when(mConnectivityManager.getTetherableIfaces()).thenReturn(new String[]{ETHERNET_REGEX}); + when(mContext.getSystemService(Context.ETHERNET_SERVICE)).thenReturn(mEthernetManager); + mController = new EthernetTetherPreferenceController(mContext, "ethernet"); + mController.setTetherEnabler(mTetherEnabler); + ReflectionHelpers.setField(mController, "mEthernetRegex", ETHERNET_REGEX); + ReflectionHelpers.setField(mController, "mPreference", mPreference); + } + + @Test + public void lifecycle_shouldRegisterReceiverOnStart() { + mController.onStart(); + + verify(mEthernetManager).addListener(eq(mController.mEthernetListener)); + } + + @Test + public void lifecycle_shouldAddListenerOnResume() { + mController.onResume(); + verify(mTetherEnabler).addListener(mController); + } + + @Test + public void lifecycle_shouldRemoveListenerOnPause() { + mController.onPause(); + verify(mTetherEnabler).removeListener(mController); + } + + @Test + public void lifecycle_shouldUnregisterReceiverOnStop() { + mController.onStart(); + EthernetManager.Listener listener = mController.mEthernetListener; + mController.onStop(); + + verify(mEthernetManager).removeListener(eq(listener)); + assertThat(mController.mEthernetListener).isNull(); + } + + @Test + public void shouldEnable_noTetherable() { + when(mConnectivityManager.getTetherableIfaces()).thenReturn(new String[0]); + assertThat(mController.shouldEnable()).isFalse(); + } + + @Test + public void shouldShow_noEthernetInterface() { + ReflectionHelpers.setField(mController, "mEthernetRegex", ""); + assertThat(mController.shouldShow()).isFalse(); + } + + @Test + public void setChecked_shouldStartEthernetTethering() { + mController.setChecked(true); + verify(mTetherEnabler).startTethering(TetheringManager.TETHERING_ETHERNET); + } + + @Test + public void setUnchecked_shouldStopEthernetTethering() { + mController.setChecked(false); + verify(mTetherEnabler).stopTethering(TetheringManager.TETHERING_ETHERNET); + } + + @Test + public void switch_shouldCheckedWhenEthernetTethering() { + mController.onTetherStateUpdated(TetherEnabler.TETHERING_ETHERNET_ON); + assertThat(mController.isChecked()).isTrue(); + } + + @Test + public void switch_shouldUnCheckedWhenEthernetNotTethering() { + 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 29d07afc859..87806bed640 100644 --- a/tests/robotests/src/com/android/settings/network/TetherEnablerTest.java +++ b/tests/robotests/src/com/android/settings/network/TetherEnablerTest.java @@ -16,6 +16,17 @@ package com.android.settings.network; +import static android.net.ConnectivityManager.TETHERING_BLUETOOTH; +import static android.net.ConnectivityManager.TETHERING_USB; +import static android.net.ConnectivityManager.TETHERING_WIFI; +import static android.net.TetheringManager.TETHERING_ETHERNET; + +import static com.android.settings.network.TetherEnabler.TETHERING_BLUETOOTH_ON; +import static com.android.settings.network.TetherEnabler.TETHERING_ETHERNET_ON; +import static com.android.settings.network.TetherEnabler.TETHERING_OFF; +import static com.android.settings.network.TetherEnabler.TETHERING_USB_ON; +import static com.android.settings.network.TetherEnabler.TETHERING_WIFI_ON; + import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; @@ -63,6 +74,8 @@ public class TetherEnablerTest { @Mock private ConnectivityManager mConnectivityManager; @Mock + private TetheringManager mTetheringManager; + @Mock private NetworkPolicyManager mNetworkPolicyManager; @Mock private BluetoothPan mBluetoothPan; @@ -85,6 +98,7 @@ public class TetherEnablerTest { when(context.getSystemService(Context.WIFI_SERVICE)).thenReturn(mWifiManager); when(context.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn( mConnectivityManager); + when(context.getSystemService(Context.TETHERING_SERVICE)).thenReturn(mTetheringManager); when(context.getSystemService(Context.NETWORK_POLICY_SERVICE)).thenReturn( mNetworkPolicyManager); when(mConnectivityManager.getTetherableIfaces()).thenReturn(new String[0]); @@ -104,6 +118,23 @@ public class TetherEnablerTest { assertThat(mSwitchBar.isChecked()).isTrue(); } + @Test + public void lifecycle_onStart_shoudRegisterTetheringEventCallback() { + mEnabler.onStart(); + verify(mTetheringManager).registerTetheringEventCallback(any(), + eq(mEnabler.mTetheringEventCallback)); + } + + @Test + public void lifecycle_onStop_shouldUnregisterTetheringEventCallback() { + mEnabler.onStart(); + TetheringManager.TetheringEventCallback callback = mEnabler.mTetheringEventCallback; + + mEnabler.onStop(); + verify(mTetheringManager).unregisterTetheringEventCallback(callback); + assertThat(mEnabler.mTetheringEventCallback).isNull(); + } + @Test public void lifecycle_onStop_resetBluetoothTetheringStoppedByUser() { mEnabler.onStart(); @@ -143,13 +174,40 @@ public class TetherEnablerTest { @Test public void onSwitchToggled_onlyStartsWifiTetherWhenNeeded() { - when(mWifiManager.isWifiApEnabled()).thenReturn(true); + doReturn(TETHERING_WIFI_ON).when(mEnabler).getTetheringState(null /* tethered */); mEnabler.onSwitchToggled(true); verify(mConnectivityManager, never()).startTethering(anyInt(), anyBoolean(), any(), any()); - doReturn(false).when(mWifiManager).isWifiApEnabled(); + doReturn(TETHERING_OFF).when(mEnabler).getTetheringState(null /* tethered */); mEnabler.onSwitchToggled(true); - verify(mConnectivityManager).startTethering(anyInt(), anyBoolean(), any(), any()); + verify(mConnectivityManager).startTethering(eq(TETHERING_WIFI), anyBoolean(), any(), any()); + verify(mConnectivityManager, never()).startTethering(eq(TETHERING_USB), anyBoolean(), any(), + any()); + verify(mConnectivityManager, never()).startTethering(eq(TETHERING_BLUETOOTH), anyBoolean(), + any(), any()); + verify(mConnectivityManager, never()).startTethering(eq(TETHERING_ETHERNET), anyBoolean(), + any(), any()); + } + + @Test + public void onSwitchToggled_stopAllTetheringInterfaces() { + mEnabler.onStart(); + + doReturn(TETHERING_WIFI_ON).when(mEnabler).getTetheringState(null /* tethered */); + mEnabler.onSwitchToggled(false); + verify(mConnectivityManager).stopTethering(TETHERING_WIFI); + + doReturn(TETHERING_USB_ON).when(mEnabler).getTetheringState(null /* tethered */); + mEnabler.onSwitchToggled(false); + verify(mConnectivityManager).stopTethering(TETHERING_USB); + + doReturn(TETHERING_BLUETOOTH_ON).when(mEnabler).getTetheringState(null /* tethered */); + mEnabler.onSwitchToggled(false); + verify(mConnectivityManager).stopTethering(TETHERING_BLUETOOTH); + + doReturn(TETHERING_ETHERNET_ON).when(mEnabler).getTetheringState(null /* tethered */); + mEnabler.onSwitchToggled(false); + verify(mConnectivityManager).stopTethering(TETHERING_ETHERNET); } @Test @@ -169,8 +227,7 @@ public class TetherEnablerTest { public void stopTethering_setBluetoothTetheringStoppedByUserAndUpdateState() { mSwitchWidgetController.setListener(mEnabler); mSwitchWidgetController.startListening(); - int state = TetherEnabler.TETHERING_BLUETOOTH_ON; - doReturn(state).when(mEnabler).getTetheringState(null /* tethered */); + doReturn(TETHERING_BLUETOOTH_ON).when(mEnabler).getTetheringState(null /* tethered */); mEnabler.stopTethering(TetheringManager.TETHERING_BLUETOOTH); assertThat(mEnabler.mBluetoothTetheringStoppedByUser).isTrue(); @@ -238,4 +295,20 @@ public class TetherEnablerTest { mEnabler.removeListener(listener); assertThat(mEnabler.mListeners).doesNotContain(listener); } + + @Test + public void isTethering_shouldReturnCorrectly() { + assertThat(TetherEnabler.isTethering(TETHERING_WIFI_ON, TETHERING_WIFI)).isTrue(); + assertThat(TetherEnabler.isTethering(~TETHERING_WIFI_ON, TETHERING_WIFI)).isFalse(); + + assertThat(TetherEnabler.isTethering(TETHERING_USB_ON, TETHERING_USB)).isTrue(); + assertThat(TetherEnabler.isTethering(~TETHERING_USB_ON, TETHERING_USB)).isFalse(); + + assertThat(TetherEnabler.isTethering(TETHERING_BLUETOOTH_ON, TETHERING_BLUETOOTH)).isTrue(); + assertThat(TetherEnabler.isTethering(~TETHERING_BLUETOOTH_ON, TETHERING_BLUETOOTH)) + .isFalse(); + + assertThat(TetherEnabler.isTethering(TETHERING_ETHERNET_ON, TETHERING_ETHERNET)).isTrue(); + assertThat(TetherEnabler.isTethering(~TETHERING_ETHERNET_ON, TETHERING_ETHERNET)).isFalse(); + } } \ 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 fbb98a4f471..066084edd85 100644 --- a/tests/robotests/src/com/android/settings/network/UsbTetherPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/network/UsbTetherPreferenceControllerTest.java @@ -16,8 +16,6 @@ package com.android.settings.network; -import static com.android.settings.network.TetherEnabler.USB_TETHER_KEY; - import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; @@ -61,7 +59,7 @@ public class UsbTetherPreferenceControllerTest { when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn( mConnectivityManager); when(mConnectivityManager.getTetherableUsbRegexs()).thenReturn(new String[]{""}); - mController = new UsbTetherPreferenceController(mContext, USB_TETHER_KEY); + mController = new UsbTetherPreferenceController(mContext, "USB"); mController.setTetherEnabler(mTetherEnabler); mSwitchPreference = spy(SwitchPreference.class); ReflectionHelpers.setField(mController, "mPreference", mSwitchPreference); @@ -95,12 +93,15 @@ public class UsbTetherPreferenceControllerTest { } @Test - public void display_availableChangedCorrectly() { - when(mConnectivityManager.getTetherableUsbRegexs()).thenReturn(new String[]{""}); - assertThat(mController.isAvailable()).isTrue(); - + public void shouldShow_noTetherableUsb() { when(mConnectivityManager.getTetherableUsbRegexs()).thenReturn(new String[0]); - assertThat(mController.isAvailable()).isFalse(); + assertThat(mController.shouldShow()).isFalse(); + } + + @Test + public void shouldEnable_noUsbConnected() { + ReflectionHelpers.setField(mController, "mUsbConnected", false); + assertThat(mController.shouldEnable()).isFalse(); } @Test diff --git a/tests/robotests/src/com/android/settings/network/WifiTetherDisablePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/WifiTetherDisablePreferenceControllerTest.java index 211f9329985..1d2042c4ae0 100644 --- a/tests/robotests/src/com/android/settings/network/WifiTetherDisablePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/network/WifiTetherDisablePreferenceControllerTest.java @@ -16,13 +16,15 @@ package com.android.settings.network; -import static com.android.settings.network.TetherEnabler.WIFI_TETHER_DISABLE_KEY; +import static com.android.settings.AllInOneTetherSettings.WIFI_TETHER_DISABLE_KEY; +import static com.android.settings.network.TetherEnabler.TETHERING_BLUETOOTH_ON; +import static com.android.settings.network.TetherEnabler.TETHERING_ETHERNET_ON; +import static com.android.settings.network.TetherEnabler.TETHERING_OFF; +import static com.android.settings.network.TetherEnabler.TETHERING_USB_ON; import static com.google.common.truth.Truth.assertThat; -import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; @@ -32,17 +34,48 @@ import androidx.preference.PreferenceScreen; import androidx.preference.SwitchPreference; import androidx.test.core.app.ApplicationProvider; +import com.android.settings.R; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.robolectric.RobolectricTestRunner; +import org.robolectric.ParameterizedRobolectricTestRunner; import org.robolectric.util.ReflectionHelpers; -@RunWith(RobolectricTestRunner.class) +import java.util.Arrays; +import java.util.List; + +@RunWith(ParameterizedRobolectricTestRunner.class) public class WifiTetherDisablePreferenceControllerTest { + @ParameterizedRobolectricTestRunner.Parameters(name = "TetherState: {0}") + public static List params() { + return Arrays.asList(new Object[][] { + {TETHERING_OFF, R.string.summary_placeholder}, + {TETHERING_USB_ON, R.string.disable_wifi_hotspot_when_usb_on}, + {TETHERING_BLUETOOTH_ON, R.string.disable_wifi_hotspot_when_bluetooth_on}, + {TETHERING_ETHERNET_ON, R.string.disable_wifi_hotspot_when_ethernet_on}, + { + TETHERING_USB_ON | TETHERING_BLUETOOTH_ON, + R.string.disable_wifi_hotspot_when_usb_and_bluetooth_on + }, + { + TETHERING_USB_ON | TETHERING_ETHERNET_ON, + R.string.disable_wifi_hotspot_when_usb_and_ethernet_on + }, + { + TETHERING_BLUETOOTH_ON | TETHERING_ETHERNET_ON, + R.string.disable_wifi_hotspot_when_bluetooth_and_ethernet_on + }, + { + TETHERING_USB_ON | TETHERING_BLUETOOTH_ON | TETHERING_ETHERNET_ON, + R.string.disable_wifi_hotspot_when_usb_and_bluetooth_and_ethernet_on + } + }); + } + @Mock private ConnectivityManager mConnectivityManager; @Mock @@ -53,6 +86,13 @@ public class WifiTetherDisablePreferenceControllerTest { private SwitchPreference mPreference; private Context mContext; private WifiTetherDisablePreferenceController mController; + private final int mTetherState; + private final int mSummaryResId; + + public WifiTetherDisablePreferenceControllerTest(int tetherState, int summaryResId) { + mTetherState = tetherState; + mSummaryResId = summaryResId; + } @Before public void setUp() { @@ -71,21 +111,16 @@ public class WifiTetherDisablePreferenceControllerTest { } @Test - public void display_availableChangedCorrectly() { + public void shouldShow_noTetherableWifi() { when(mConnectivityManager.getTetherableWifiRegexs()).thenReturn(new String[0]); - assertThat(mController.isAvailable()).isFalse(); - - when(mConnectivityManager.getTetherableWifiRegexs()).thenReturn(new String[]{"test"}); - ReflectionHelpers.setField(mController, "mBluetoothTethering", false); - ReflectionHelpers.setField(mController, "mUsbTethering", false); - assertThat(mController.isAvailable()).isFalse(); + assertThat(mController.shouldShow()).isFalse(); } @Test - public void switch_shouldListenToUsbAndBluetooth() { + public void onTetherStateUpdated_visibilityChangeCorrectly() { int state = TetherEnabler.TETHERING_BLUETOOTH_ON; mController.onTetherStateUpdated(state); - verify(mPreference).setVisible(eq(true)); + assertThat(mController.shouldShow()).isTrue(); state |= TetherEnabler.TETHERING_USB_ON; mController.onTetherStateUpdated(state); @@ -97,6 +132,12 @@ public class WifiTetherDisablePreferenceControllerTest { state = TetherEnabler.TETHERING_OFF; mController.onTetherStateUpdated(state); - verify(mPreference).setVisible(eq(false)); + assertThat(mController.shouldShow()).isFalse(); + } + + @Test + public void getSummary_onTetherStateUpdated() { + mController.onTetherStateUpdated(mTetherState); + assertThat(mController.getSummary()).isEqualTo(mContext.getString(mSummaryResId)); } }