From bcca5ebf1a5eae2dbbd59500e54cb38b7e494313 Mon Sep 17 00:00:00 2001 From: Weng Su Date: Tue, 7 Mar 2023 23:38:38 +0800 Subject: [PATCH] Add "Speed & compatibility" preference to Wi-Fi hotspot Settings - Show 4 speed types in summary - 2.4 Ghz - 5 Ghz - 2.4 and 5 GHz - 6 GHz Bug: 245258763 Test: manual test atest -c WifiTetherViewModelTest atest -c WifiHotspotRepositoryTest make RunSettingsRoboTests ROBOTEST_FILTER=WifiTetherSettingsTest Change-Id: I6deb41cb355b0ceb1f1fd2d84408a83b90433e7d --- res/values/config.xml | 3 + res/values/strings.xml | 10 + res/xml/wifi_tether_settings.xml | 6 + .../wifi/factory/WifiFeatureProvider.java | 13 ++ .../repository/WifiHotspotRepository.java | 215 ++++++++++++++++++ .../wifi/tether/WifiTetherSettings.java | 22 +- .../wifi/tether/WifiTetherViewModel.java | 103 +++++++++ .../wifi/tether/WifiTetherSettingsTest.java | 23 ++ .../repository/WifiHotspotRepositoryTest.java | 188 +++++++++++++++ .../wifi/tether/WifiTetherViewModelTest.java | 108 +++++++++ 10 files changed, 690 insertions(+), 1 deletion(-) create mode 100644 src/com/android/settings/wifi/tether/WifiTetherViewModel.java create mode 100644 tests/unit/src/com/android/settings/wifi/tether/WifiTetherViewModelTest.java diff --git a/res/values/config.xml b/res/values/config.xml index 43643d35266..ef786be59eb 100755 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -363,6 +363,9 @@ true + + false + true diff --git a/res/values/strings.xml b/res/values/strings.xml index 86bbb0614f9..a79b1d4d877 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -2015,6 +2015,16 @@ Helps other devices find this hotspot. Reduces hotspot connection speed. Helps other devices find this hotspot. Increases battery usage. + + Speed & compatibility + + 2.4 GHz / Any device can connect + + 5 GHz / Most devices can connect + + 6 GHz / Few devices can connect + + 2.4 and 5 GHz / Any device can connect Turning hotspot on\u2026 diff --git a/res/xml/wifi_tether_settings.xml b/res/xml/wifi_tether_settings.xml index 21f347bb021..1cd5f48ca0d 100644 --- a/res/xml/wifi_tether_settings.xml +++ b/res/xml/wifi_tether_settings.xml @@ -45,4 +45,10 @@ + + diff --git a/src/com/android/settings/wifi/factory/WifiFeatureProvider.java b/src/com/android/settings/wifi/factory/WifiFeatureProvider.java index 2f5f3ea88a3..433ff0c07ad 100644 --- a/src/com/android/settings/wifi/factory/WifiFeatureProvider.java +++ b/src/com/android/settings/wifi/factory/WifiFeatureProvider.java @@ -20,8 +20,13 @@ import android.content.Context; import android.net.wifi.WifiManager; import androidx.annotation.NonNull; +import androidx.lifecycle.ViewModelProvider; +import androidx.lifecycle.ViewModelStoreOwner; import com.android.settings.wifi.repository.WifiHotspotRepository; +import com.android.settings.wifi.tether.WifiTetherViewModel; + +import org.jetbrains.annotations.NotNull; /** * Wi-Fi Feature Provider @@ -55,5 +60,13 @@ public class WifiFeatureProvider { } return mWifiHotspotRepository; } + + /** + * Get WifiTetherViewModel + */ + public WifiTetherViewModel getWifiTetherViewModel(@NotNull ViewModelStoreOwner owner) { + return new ViewModelProvider(owner).get(WifiTetherViewModel.class); + } + } diff --git a/src/com/android/settings/wifi/repository/WifiHotspotRepository.java b/src/com/android/settings/wifi/repository/WifiHotspotRepository.java index b8a25dc84be..ee1ceea600e 100644 --- a/src/com/android/settings/wifi/repository/WifiHotspotRepository.java +++ b/src/com/android/settings/wifi/repository/WifiHotspotRepository.java @@ -16,13 +16,27 @@ package com.android.settings.wifi.repository; +import static android.net.wifi.SoftApConfiguration.BAND_2GHZ; +import static android.net.wifi.SoftApConfiguration.BAND_5GHZ; +import static android.net.wifi.SoftApConfiguration.BAND_6GHZ; +import static android.net.wifi.WifiAvailableChannel.OP_MODE_SAP; + import android.content.Context; import android.net.wifi.SoftApConfiguration; +import android.net.wifi.WifiAvailableChannel; import android.net.wifi.WifiManager; +import android.net.wifi.WifiScanner; import android.text.TextUtils; +import android.util.Log; import androidx.annotation.NonNull; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; +import androidx.lifecycle.Transformations; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.UUID; import java.util.function.Consumer; @@ -30,6 +44,36 @@ import java.util.function.Consumer; * Wi-Fi Hotspot Repository */ public class WifiHotspotRepository { + private static final String TAG = "WifiHotspotRepository"; + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + + /** Wi-Fi hotspot band unknown. */ + public static final int BAND_UNKNOWN = 0; + /** Wi-Fi hotspot band 2.4GHz and 5GHz. */ + public static final int BAND_2GHZ_5GHZ = BAND_2GHZ | BAND_5GHZ; + /** Wi-Fi hotspot band 2.4GHz and 5GHz and 6GHz. */ + public static final int BAND_2GHZ_5GHZ_6GHZ = BAND_2GHZ | BAND_5GHZ | BAND_6GHZ; + + /** Wi-Fi hotspot speed unknown. */ + public static final int SPEED_UNKNOWN = 0; + /** Wi-Fi hotspot speed 2.4GHz. */ + public static final int SPEED_2GHZ = 1; + /** Wi-Fi hotspot speed 5GHz. */ + public static final int SPEED_5GHZ = 2; + /** Wi-Fi hotspot speed 2.4GHz and 5GHz. */ + public static final int SPEED_2GHZ_5GHZ = 3; + /** Wi-Fi hotspot speed 6GHz. */ + public static final int SPEED_6GHZ = 4; + + protected static Map sSpeedMap = new HashMap<>(); + + static { + sSpeedMap.put(BAND_UNKNOWN, SPEED_UNKNOWN); + sSpeedMap.put(BAND_2GHZ, SPEED_2GHZ); + sSpeedMap.put(BAND_5GHZ, SPEED_5GHZ); + sSpeedMap.put(BAND_6GHZ, SPEED_6GHZ); + sSpeedMap.put(BAND_2GHZ_5GHZ, SPEED_2GHZ_5GHZ); + } protected final Context mAppContext; protected final WifiManager mWifiManager; @@ -37,6 +81,14 @@ public class WifiHotspotRepository { protected String mLastPassword; protected LastPasswordListener mLastPasswordListener = new LastPasswordListener(); + protected MutableLiveData mSpeedType; + + protected Boolean mIsDualBand; + protected Boolean mIs5gAvailable; + protected Boolean mIs6gAvailable; + protected String mCurrentCountryCode; + protected ActiveCountryCodeChangedCallback mActiveCountryCodeChangedCallback; + public WifiHotspotRepository(@NonNull Context appContext, @NonNull WifiManager wifiManager) { mAppContext = appContext; mWifiManager = wifiManager; @@ -73,4 +125,167 @@ public class WifiHotspotRepository { //first 12 chars from xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx return randomUUID.substring(0, 8) + randomUUID.substring(9, 13); } + + /** + * Sets the tethered Wi-Fi AP Configuration. + * + * @param config A valid SoftApConfiguration specifying the configuration of the SAP. + */ + public void setSoftApConfiguration(@NonNull SoftApConfiguration config) { + mWifiManager.setSoftApConfiguration(config); + refresh(); + } + + /** + * Refresh data from the SoftApConfiguration. + */ + public void refresh() { + updateSpeedType(); + } + + /** + * Set to auto refresh data. + * + * @param enabled whether the auto refresh should be enabled or not. + */ + public void setAutoRefresh(boolean enabled) { + if (enabled) { + startAutoRefresh(); + } else { + stopAutoRefresh(); + } + } + + /** + * Gets SpeedType LiveData + */ + public LiveData getSpeedType() { + if (mSpeedType == null) { + mSpeedType = new MutableLiveData<>(); + updateSpeedType(); + } + return Transformations.distinctUntilChanged(mSpeedType); + } + + protected void updateSpeedType() { + if (mSpeedType == null) { + return; + } + SoftApConfiguration config = mWifiManager.getSoftApConfiguration(); + if (config == null) { + mSpeedType.setValue(SPEED_UNKNOWN); + return; + } + int keyBand = config.getBand(); + logd("updateSpeedType(), getBand():" + keyBand); + if (!is5gAvailable()) { + keyBand &= ~BAND_5GHZ; + } + if (!is6gAvailable()) { + keyBand &= ~BAND_6GHZ; + } + if ((keyBand & BAND_6GHZ) != 0) { + keyBand = BAND_6GHZ; + } else if (isDualBand() && is5gAvailable()) { + keyBand = BAND_2GHZ_5GHZ; + } else if ((keyBand & BAND_5GHZ) != 0) { + keyBand = BAND_5GHZ; + } else if ((keyBand & BAND_2GHZ) != 0) { + keyBand = BAND_2GHZ; + } else { + keyBand = 0; + } + logd("updateSpeedType(), keyBand:" + keyBand); + mSpeedType.setValue(sSpeedMap.get(keyBand)); + } + + protected boolean isDualBand() { + if (mIsDualBand == null) { + mIsDualBand = mWifiManager.isBridgedApConcurrencySupported(); + logd("isDualBand():" + mIsDualBand); + } + return mIsDualBand; + } + + protected boolean is5gAvailable() { + if (mIs5gAvailable == null) { + // TODO(b/272450463): isBandAvailable(WifiScanner.WIFI_BAND_5_GHZ_WITH_DFS) will + // cause crash in the old model device, use a simple check to workaround it first. + mIs5gAvailable = (mWifiManager.is5GHzBandSupported() && mCurrentCountryCode != null); + logd("is5gAvailable():" + mIs5gAvailable); + } + return mIs5gAvailable; + } + + protected boolean is6gAvailable() { + if (mIs6gAvailable == null) { + mIs6gAvailable = mWifiManager.is6GHzBandSupported() + && isBandAvailable(WifiScanner.WIFI_BAND_6_GHZ); + logd("is6gAvailable():" + mIs6gAvailable); + } + return mIs6gAvailable; + } + + /** + * Return whether the Hotspot band is available or not. + * + * @param band one of the following band constants defined in {@code WifiScanner#WIFI_BAND_*} + * constants. + * 1. {@code WifiScanner#WIFI_BAND_5_GHZ_WITH_DFS} + * 2. {@code WifiScanner#WIFI_BAND_6_GHZ} + */ + protected boolean isBandAvailable(int band) { + List channels = mWifiManager.getUsableChannels(band, OP_MODE_SAP); + return (channels != null && channels.size() > 0); + } + + protected void purgeRefreshData() { + mIsDualBand = null; + mIs5gAvailable = null; + mIs6gAvailable = null; + } + + protected void startAutoRefresh() { + if (mActiveCountryCodeChangedCallback != null) { + return; + } + logd("startMonitorSoftApConfiguration()"); + mActiveCountryCodeChangedCallback = new ActiveCountryCodeChangedCallback(); + mWifiManager.registerActiveCountryCodeChangedCallback(mAppContext.getMainExecutor(), + mActiveCountryCodeChangedCallback); + } + + protected void stopAutoRefresh() { + if (mActiveCountryCodeChangedCallback == null) { + return; + } + logd("stopMonitorSoftApConfiguration()"); + mWifiManager.unregisterActiveCountryCodeChangedCallback(mActiveCountryCodeChangedCallback); + mActiveCountryCodeChangedCallback = null; + } + + protected class ActiveCountryCodeChangedCallback implements + WifiManager.ActiveCountryCodeChangedCallback { + @Override + public void onActiveCountryCodeChanged(String country) { + logd("onActiveCountryCodeChanged(), country:" + country); + mCurrentCountryCode = country; + purgeRefreshData(); + refresh(); + } + + @Override + public void onCountryCodeInactive() { + logd("onCountryCodeInactive()"); + mCurrentCountryCode = null; + purgeRefreshData(); + refresh(); + } + } + + private static void logd(String msg) { + if (DEBUG) { + Log.d(TAG, msg); + } + } } diff --git a/src/com/android/settings/wifi/tether/WifiTetherSettings.java b/src/com/android/settings/wifi/tether/WifiTetherSettings.java index 47dba765e5f..3a3691a4b30 100644 --- a/src/com/android/settings/wifi/tether/WifiTetherSettings.java +++ b/src/com/android/settings/wifi/tether/WifiTetherSettings.java @@ -34,11 +34,13 @@ import android.util.Log; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; +import androidx.preference.Preference; import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.core.FeatureFlags; import com.android.settings.dashboard.RestrictedDashboardFragment; +import com.android.settings.overlay.FeatureFactory; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.widget.SettingsMainSwitchBar; import com.android.settings.wifi.WifiUtils; @@ -69,6 +71,8 @@ public class WifiTetherSettings extends RestrictedDashboardFragment @VisibleForTesting static final String KEY_WIFI_TETHER_MAXIMIZE_COMPATIBILITY = WifiTetherMaximizeCompatibilityPreferenceController.PREF_KEY; + @VisibleForTesting + static final String KEY_WIFI_HOTSPOT_SPEED = "wifi_hotspot_speed"; private WifiTetherSwitchBarController mSwitchBarController; private WifiTetherSSIDPreferenceController mSSIDPreferenceController; @@ -84,6 +88,11 @@ public class WifiTetherSettings extends RestrictedDashboardFragment @VisibleForTesting TetherChangeReceiver mTetherChangeReceiver; + @VisibleForTesting + WifiTetherViewModel mWifiTetherViewModel; + @VisibleForTesting + Preference mWifiHotspotSpeed; + static { TETHER_STATE_CHANGE_FILTER = new IntentFilter(WIFI_AP_STATE_CHANGED_ACTION); } @@ -120,6 +129,13 @@ public class WifiTetherSettings extends RestrictedDashboardFragment setIfOnlyAvailableForAdmins(true); mUnavailable = isUiRestricted() || !mWifiRestriction.isHotspotAvailable(getContext()); + + mWifiTetherViewModel = FeatureFactory.getFactory(getContext()).getWifiFeatureProvider() + .getWifiTetherViewModel(this); + mWifiHotspotSpeed = findPreference(KEY_WIFI_HOTSPOT_SPEED); + if (mWifiHotspotSpeed != null && mWifiHotspotSpeed.isVisible()) { + mWifiTetherViewModel.getSpeedSummary().observe(this, this::onSpeedSummaryChanged); + } } @Override @@ -175,6 +191,7 @@ public class WifiTetherSettings extends RestrictedDashboardFragment // Handle the initial state after register the receiver. updateDisplayWithNewConfig(); } + mWifiTetherViewModel.refresh(); } @Override @@ -189,6 +206,9 @@ public class WifiTetherSettings extends RestrictedDashboardFragment } } + protected void onSpeedSummaryChanged(Integer summaryResId) { + mWifiHotspotSpeed.setSummary(summaryResId); + } @Override protected int getPreferenceScreenResId() { @@ -228,7 +248,7 @@ public class WifiTetherSettings extends RestrictedDashboardFragment mRestartWifiApAfterConfigChange = true; mSwitchBarController.stopTether(); } - mWifiManager.setSoftApConfiguration(config); + mWifiTetherViewModel.setSoftApConfiguration(config); } private SoftApConfiguration buildNewConfig() { diff --git a/src/com/android/settings/wifi/tether/WifiTetherViewModel.java b/src/com/android/settings/wifi/tether/WifiTetherViewModel.java new file mode 100644 index 00000000000..4abca023606 --- /dev/null +++ b/src/com/android/settings/wifi/tether/WifiTetherViewModel.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2023 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.wifi.tether; + +import static com.android.settings.wifi.repository.WifiHotspotRepository.SPEED_2GHZ; +import static com.android.settings.wifi.repository.WifiHotspotRepository.SPEED_2GHZ_5GHZ; +import static com.android.settings.wifi.repository.WifiHotspotRepository.SPEED_5GHZ; +import static com.android.settings.wifi.repository.WifiHotspotRepository.SPEED_6GHZ; +import static com.android.settings.wifi.repository.WifiHotspotRepository.SPEED_UNKNOWN; + +import android.app.Application; +import android.net.wifi.SoftApConfiguration; + +import androidx.lifecycle.AndroidViewModel; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; +import androidx.lifecycle.Transformations; + +import com.android.settings.R; +import com.android.settings.overlay.FeatureFactory; +import com.android.settings.wifi.repository.WifiHotspotRepository; + +import org.jetbrains.annotations.NotNull; + +import java.util.HashMap; +import java.util.Map; + +/** + * Wi-Fi Hotspot ViewModel + */ +public class WifiTetherViewModel extends AndroidViewModel { + private static final String TAG = "WifiTetherViewModel"; + + protected static Map sSpeedSummaryResMap = new HashMap<>(); + + static { + sSpeedSummaryResMap.put(SPEED_UNKNOWN, R.string.summary_placeholder); + sSpeedSummaryResMap.put(SPEED_2GHZ, R.string.wifi_hotspot_speed_2g_summary); + sSpeedSummaryResMap.put(SPEED_5GHZ, R.string.wifi_hotspot_speed_5g_summary); + sSpeedSummaryResMap.put(SPEED_6GHZ, R.string.wifi_hotspot_speed_6g_summary); + sSpeedSummaryResMap.put(SPEED_2GHZ_5GHZ, R.string.wifi_hotspot_speed_2g_and_5g_summary); + } + + protected final WifiHotspotRepository mWifiHotspotRepository; + protected MutableLiveData mSpeedSummary; + + public WifiTetherViewModel(@NotNull Application application) { + super(application); + mWifiHotspotRepository = FeatureFactory.getFactory(application).getWifiFeatureProvider() + .getWifiHotspotRepository(); + mWifiHotspotRepository.setAutoRefresh(true); + } + + @Override + protected void onCleared() { + mWifiHotspotRepository.setAutoRefresh(false); + } + + /** + * Sets the tethered Wi-Fi AP Configuration. + * + * @param config A valid SoftApConfiguration specifying the configuration of the SAP. + */ + public void setSoftApConfiguration(SoftApConfiguration config) { + mWifiHotspotRepository.setSoftApConfiguration(config); + } + + /** + * Refresh data from the SoftApConfiguration. + */ + public void refresh() { + mWifiHotspotRepository.refresh(); + } + + /** + * Gets SpeedSummary LiveData + */ + public LiveData getSpeedSummary() { + if (mSpeedSummary == null) { + mSpeedSummary = new MutableLiveData<>(); + mWifiHotspotRepository.getSpeedType().observeForever(this::onSpeedTypeChanged); + } + return Transformations.distinctUntilChanged(mSpeedSummary); + } + + protected void onSpeedTypeChanged(Integer speedType) { + mSpeedSummary.setValue(sSpeedSummaryResMap.get(speedType)); + } +} diff --git a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java index 7f8a06d1521..582f792b788 100644 --- a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java +++ b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java @@ -41,6 +41,8 @@ import android.util.FeatureFlagUtils; import android.widget.TextView; import androidx.fragment.app.FragmentActivity; +import androidx.lifecycle.ViewModelStoreOwner; +import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import androidx.test.core.app.ApplicationProvider; @@ -49,6 +51,8 @@ import com.android.settings.core.FeatureFlags; import com.android.settings.dashboard.RestrictedDashboardFragment; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.shadow.ShadowFragment; +import com.android.settings.wifi.factory.WifiFeatureProvider; +import com.android.settings.wifi.repository.WifiHotspotRepository; import org.junit.Before; import org.junit.Rule; @@ -90,6 +94,10 @@ public class WifiTetherSettingsTest { private PreferenceScreen mPreferenceScreen; @Mock private TextView mEmptyTextView; + @Mock + WifiTetherViewModel mWifiTetherViewModel; + @Mock + WifiHotspotRepository mWifiHotspotRepository; private WifiTetherSettings mWifiTetherSettings; @@ -106,6 +114,11 @@ public class WifiTetherSettingsTest { when(mWifiRestriction.isTetherAvailable(mContext)).thenReturn(true); when(mWifiRestriction.isHotspotAvailable(mContext)).thenReturn(true); + WifiFeatureProvider provider = FakeFeatureFactory.setupForTest().getWifiFeatureProvider(); + when(provider.getWifiHotspotRepository()).thenReturn(mWifiHotspotRepository); + when(provider.getWifiTetherViewModel(mock(ViewModelStoreOwner.class))) + .thenReturn(mWifiTetherViewModel); + mWifiTetherSettings = new WifiTetherSettings(mWifiRestriction); } @@ -142,6 +155,16 @@ public class WifiTetherSettingsTest { verify(mEmptyTextView).setText(anyInt()); } + @Test + public void onSpeedSummaryChanged_canNotShowWifiHotspot_returnFalse() { + int stringResId = R.string.wifi_hotspot_speed_6g_summary; + mWifiTetherSettings.mWifiHotspotSpeed = mock(Preference.class); + + mWifiTetherSettings.onSpeedSummaryChanged(stringResId); + + verify(mWifiTetherSettings.mWifiHotspotSpeed).setSummary(stringResId); + } + @Test public void createPreferenceControllers_getPreferenceControllersNotEmpty() { assertThat(WifiTetherSettings.SEARCH_INDEX_DATA_PROVIDER.getPreferenceControllers(mContext)) diff --git a/tests/unit/src/com/android/settings/wifi/repository/WifiHotspotRepositoryTest.java b/tests/unit/src/com/android/settings/wifi/repository/WifiHotspotRepositoryTest.java index 58a9d1c87a2..52f02f5f14a 100644 --- a/tests/unit/src/com/android/settings/wifi/repository/WifiHotspotRepositoryTest.java +++ b/tests/unit/src/com/android/settings/wifi/repository/WifiHotspotRepositoryTest.java @@ -16,12 +16,21 @@ package com.android.settings.wifi.repository; +import static android.net.wifi.SoftApConfiguration.BAND_2GHZ; import static android.net.wifi.SoftApConfiguration.SECURITY_TYPE_OPEN; import static android.net.wifi.SoftApConfiguration.SECURITY_TYPE_WPA3_SAE; +import static com.android.settings.wifi.repository.WifiHotspotRepository.BAND_2GHZ_5GHZ; +import static com.android.settings.wifi.repository.WifiHotspotRepository.BAND_2GHZ_5GHZ_6GHZ; +import static com.android.settings.wifi.repository.WifiHotspotRepository.SPEED_2GHZ; +import static com.android.settings.wifi.repository.WifiHotspotRepository.SPEED_2GHZ_5GHZ; +import static com.android.settings.wifi.repository.WifiHotspotRepository.SPEED_5GHZ; +import static com.android.settings.wifi.repository.WifiHotspotRepository.SPEED_6GHZ; + import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -30,6 +39,8 @@ import android.content.Context; import android.net.wifi.SoftApConfiguration; import android.net.wifi.WifiManager; +import androidx.lifecycle.MutableLiveData; +import androidx.test.annotation.UiThreadTest; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; @@ -46,6 +57,10 @@ import org.mockito.junit.MockitoRule; public class WifiHotspotRepositoryTest { static final String WIFI_SSID = "wifi_ssid"; static final String WIFI_PASSWORD = "wifi_password"; + static final String WIFI_CURRENT_COUNTRY_CODE = "US"; + + static final int WIFI_5GHZ_BAND_PREFERRED = BAND_2GHZ_5GHZ; + static final int WIFI_6GHZ_BAND_PREFERRED = BAND_2GHZ_5GHZ_6GHZ; @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule(); @@ -53,6 +68,8 @@ public class WifiHotspotRepositoryTest { Context mContext = ApplicationProvider.getApplicationContext(); @Mock WifiManager mWifiManager; + @Mock + MutableLiveData mSpeedType; WifiHotspotRepository mWifiHotspotRepository; SoftApConfiguration mSoftApConfiguration; @@ -60,6 +77,10 @@ public class WifiHotspotRepositoryTest { @Before public void setUp() { mWifiHotspotRepository = new WifiHotspotRepository(mContext, mWifiManager); + mWifiHotspotRepository.mCurrentCountryCode = WIFI_CURRENT_COUNTRY_CODE; + mWifiHotspotRepository.mIsDualBand = true; + mWifiHotspotRepository.mIs5gAvailable = true; + mWifiHotspotRepository.mIs6gAvailable = true; } @Test @@ -105,4 +126,171 @@ public class WifiHotspotRepositoryTest { assertThat(password).isNotEqualTo(WIFI_PASSWORD); assertThat(password.length()).isNotEqualTo(0); } + + @Test + public void setSoftApConfiguration_setConfigByWifiManager() { + SoftApConfiguration config = new SoftApConfiguration.Builder().build(); + + mWifiHotspotRepository.setSoftApConfiguration(config); + + verify(mWifiManager).setSoftApConfiguration(config); + } + + @Test + public void refresh_liveDataNotUsed_doNothing() { + // If LiveData is not used then it's null. + mWifiHotspotRepository.mSpeedType = null; + + mWifiHotspotRepository.refresh(); + + verify(mWifiManager, never()).getSoftApConfiguration(); + } + + @Test + public void refresh_liveDataIsUsed_getConfigAndUpdateLiveData() { + // If LiveData is used then it's not null. + mWifiHotspotRepository.mSpeedType = mSpeedType; + + mWifiHotspotRepository.refresh(); + + verify(mWifiManager).getSoftApConfiguration(); + verify(mSpeedType).setValue(anyInt()); + } + + @Test + public void setAutoRefresh_setEnabled_registerCallback() { + mWifiHotspotRepository.mActiveCountryCodeChangedCallback = null; + + mWifiHotspotRepository.setAutoRefresh(true); + + verify(mWifiManager).registerActiveCountryCodeChangedCallback(any(), any()); + } + + @Test + public void setAutoRefresh_setDisabled_registerCallback() { + mWifiHotspotRepository.setAutoRefresh(true); + + mWifiHotspotRepository.setAutoRefresh(false); + + verify(mWifiManager).unregisterActiveCountryCodeChangedCallback(any()); + } + + @Test + @UiThreadTest + public void getSpeedType_shouldNotReturnNull() { + // If LiveData is not used then it's null. + mWifiHotspotRepository.mSpeedType = null; + SoftApConfiguration config = new SoftApConfiguration.Builder().setBand(BAND_2GHZ).build(); + when(mWifiManager.getSoftApConfiguration()).thenReturn(config); + + assertThat(mWifiHotspotRepository.getSpeedType()).isNotNull(); + } + + @Test + public void updateSpeedType_singleBand2g_get2gSpeedType() { + mWifiHotspotRepository.mIsDualBand = false; + SoftApConfiguration config = new SoftApConfiguration.Builder().setBand(BAND_2GHZ).build(); + when(mWifiManager.getSoftApConfiguration()).thenReturn(config); + mWifiHotspotRepository.mSpeedType = mSpeedType; + + mWifiHotspotRepository.updateSpeedType(); + + verify(mSpeedType).setValue(SPEED_2GHZ); + } + + @Test + public void updateSpeedType_singleBand5gPreferred_get5gSpeedType() { + mWifiHotspotRepository.mIsDualBand = false; + SoftApConfiguration config = new SoftApConfiguration.Builder() + .setBand(WIFI_5GHZ_BAND_PREFERRED).build(); + when(mWifiManager.getSoftApConfiguration()).thenReturn(config); + mWifiHotspotRepository.mSpeedType = mSpeedType; + + mWifiHotspotRepository.updateSpeedType(); + + verify(mSpeedType).setValue(SPEED_5GHZ); + } + + @Test + public void updateSpeedType_singleBand5gPreferredBut5gUnavailable_get2gSpeedType() { + mWifiHotspotRepository.mIsDualBand = false; + mWifiHotspotRepository.mIs5gAvailable = false; + SoftApConfiguration config = new SoftApConfiguration.Builder() + .setBand(WIFI_5GHZ_BAND_PREFERRED).build(); + when(mWifiManager.getSoftApConfiguration()).thenReturn(config); + mWifiHotspotRepository.mSpeedType = mSpeedType; + + mWifiHotspotRepository.updateSpeedType(); + + verify(mSpeedType).setValue(SPEED_2GHZ); + } + + @Test + public void updateSpeedType_singleBand6gPreferred_get6gSpeedType() { + mWifiHotspotRepository.mIsDualBand = false; + SoftApConfiguration config = new SoftApConfiguration.Builder() + .setBand(WIFI_6GHZ_BAND_PREFERRED).build(); + when(mWifiManager.getSoftApConfiguration()).thenReturn(config); + mWifiHotspotRepository.mSpeedType = mSpeedType; + + mWifiHotspotRepository.updateSpeedType(); + + verify(mSpeedType).setValue(SPEED_6GHZ); + } + + @Test + public void updateSpeedType_singleBand6gPreferredBut6gUnavailable_get5gSpeedType() { + mWifiHotspotRepository.mIsDualBand = false; + mWifiHotspotRepository.mIs6gAvailable = false; + SoftApConfiguration config = new SoftApConfiguration.Builder() + .setBand(WIFI_6GHZ_BAND_PREFERRED).build(); + when(mWifiManager.getSoftApConfiguration()).thenReturn(config); + mWifiHotspotRepository.mSpeedType = mSpeedType; + + mWifiHotspotRepository.updateSpeedType(); + + verify(mSpeedType).setValue(SPEED_5GHZ); + } + + @Test + public void updateSpeedType_singleBand6gPreferredBut5gAnd6gUnavailable_get2gSpeedType() { + mWifiHotspotRepository.mIsDualBand = false; + mWifiHotspotRepository.mIs5gAvailable = false; + mWifiHotspotRepository.mIs6gAvailable = false; + SoftApConfiguration config = new SoftApConfiguration.Builder() + .setBand(WIFI_6GHZ_BAND_PREFERRED).build(); + when(mWifiManager.getSoftApConfiguration()).thenReturn(config); + mWifiHotspotRepository.mSpeedType = mSpeedType; + + mWifiHotspotRepository.updateSpeedType(); + + verify(mSpeedType).setValue(SPEED_2GHZ); + } + + @Test + public void updateSpeedType_dualBand2gAnd5g_get2gAnd5gSpeedType() { + mWifiHotspotRepository.mIsDualBand = true; + SoftApConfiguration config = new SoftApConfiguration.Builder() + .setBand(WIFI_5GHZ_BAND_PREFERRED).build(); + when(mWifiManager.getSoftApConfiguration()).thenReturn(config); + mWifiHotspotRepository.mSpeedType = mSpeedType; + + mWifiHotspotRepository.updateSpeedType(); + + verify(mSpeedType).setValue(SPEED_2GHZ_5GHZ); + } + + @Test + public void updateSpeedType_dualBand2gAnd5gBut5gUnavailable_get2gSpeedType() { + mWifiHotspotRepository.mIsDualBand = true; + mWifiHotspotRepository.mIs5gAvailable = false; + SoftApConfiguration config = new SoftApConfiguration.Builder() + .setBand(WIFI_5GHZ_BAND_PREFERRED).build(); + when(mWifiManager.getSoftApConfiguration()).thenReturn(config); + mWifiHotspotRepository.mSpeedType = mSpeedType; + + mWifiHotspotRepository.updateSpeedType(); + + verify(mSpeedType).setValue(SPEED_2GHZ); + } } diff --git a/tests/unit/src/com/android/settings/wifi/tether/WifiTetherViewModelTest.java b/tests/unit/src/com/android/settings/wifi/tether/WifiTetherViewModelTest.java new file mode 100644 index 00000000000..6724dd5178c --- /dev/null +++ b/tests/unit/src/com/android/settings/wifi/tether/WifiTetherViewModelTest.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2023 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.wifi.tether; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.Application; +import android.net.wifi.SoftApConfiguration; + +import androidx.lifecycle.MutableLiveData; +import androidx.test.annotation.UiThreadTest; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import com.android.settings.testutils.FakeFeatureFactory; +import com.android.settings.wifi.repository.WifiHotspotRepository; + +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 java.util.concurrent.Executor; + +@RunWith(AndroidJUnit4.class) +public class WifiTetherViewModelTest { + @Rule + public final MockitoRule mMockitoRule = MockitoJUnit.rule(); + @Mock + Application mApplication; + @Mock + Executor mExecutor; + @Mock + WifiHotspotRepository mWifiHotspotRepository; + @Mock + MutableLiveData mSpeedType; + + WifiTetherViewModel mViewModel; + + @Before + public void setUp() { + when(mApplication.getMainExecutor()).thenReturn(mExecutor); + + FakeFeatureFactory featureFactory = FakeFeatureFactory.setupForTest(); + when(featureFactory.getWifiFeatureProvider().getWifiHotspotRepository()) + .thenReturn(mWifiHotspotRepository); + when(mWifiHotspotRepository.getSpeedType()).thenReturn(mSpeedType); + + mViewModel = new WifiTetherViewModel(mApplication); + } + + @Test + public void constructor_setAutoRefreshTrue() { + verify(mWifiHotspotRepository).setAutoRefresh(true); + } + + @Test + public void onCleared_setAutoRefreshFalse() { + mViewModel.onCleared(); + + verify(mWifiHotspotRepository).setAutoRefresh(false); + } + + @Test + public void setSoftApConfiguration_setConfigByRepository() { + SoftApConfiguration config = new SoftApConfiguration.Builder().build(); + + mViewModel.setSoftApConfiguration(config); + + verify(mWifiHotspotRepository).setSoftApConfiguration(config); + } + + @Test + public void refresh_refreshByRepository() { + mViewModel.refresh(); + + verify(mWifiHotspotRepository).refresh(); + } + + @Test + @UiThreadTest + public void getSpeedSummary_returnNotNull() { + mViewModel.mSpeedSummary = null; + + mViewModel.getSpeedSummary(); + + assertThat(mViewModel.mSpeedSummary).isNotNull(); + } +}