diff --git a/res/values/strings.xml b/res/values/strings.xml
index 197672db02f..b7fb0134f51 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -2018,13 +2018,37 @@
Speed & compatibility
- 2.4 GHz / Any device can connect
+ 2.4 GHz / Any device can connect
- 5 GHz / Most devices can connect
+ 5 GHz / Most devices can connect
- 6 GHz / Few devices can connect
+ 6 GHz / Few devices can connect
- 2.4 and 5 GHz / Any device can connect
+ 2.4 and 5 GHz / Any device can connect
+
+ Choose a frequency for your hotspot. The frequency affects the connection speed and what types of devices can find your hotspot.
+
+ Preferred frequency
+
+ 2.4 GHz
+
+ Slower speeds. Any device can connect.
+
+ 5 GHz
+
+ Fast speeds. Most devices can connect.
+
+ 2.4 and 5 GHz
+
+ Fast speeds. Any device can connect to this dual-band hotspot.
+
+ 6 GHz
+
+ Fastest speeds. Fewest devices can connect.
+
+ Not available in your country or region
+
+ If your preferred frequency isn\u0027t available, your hotspot may use a different one. Hotspot security settings may change if you change the frequency.
Turning hotspot on\u2026
diff --git a/res/xml/wifi_hotspot_speed.xml b/res/xml/wifi_hotspot_speed.xml
new file mode 100644
index 00000000000..b19a5b94483
--- /dev/null
+++ b/res/xml/wifi_hotspot_speed.xml
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/res/xml/wifi_tether_settings.xml b/res/xml/wifi_tether_settings.xml
index 1cd5f48ca0d..3023a6e10bd 100644
--- a/res/xml/wifi_tether_settings.xml
+++ b/res/xml/wifi_tether_settings.xml
@@ -50,5 +50,6 @@
android:key="wifi_hotspot_speed"
android:title="@string/wifi_hotspot_speed_title"
android:summary="@string/summary_placeholder"
+ android:fragment="com.android.settings.wifi.tether.WifiHotspotSpeedSettings"
settings:isPreferenceVisible="@bool/config_show_wifi_hotspot_speed"/>
diff --git a/src/com/android/settings/wifi/factory/WifiFeatureProvider.java b/src/com/android/settings/wifi/factory/WifiFeatureProvider.java
index 433ff0c07ad..ea15c4359e4 100644
--- a/src/com/android/settings/wifi/factory/WifiFeatureProvider.java
+++ b/src/com/android/settings/wifi/factory/WifiFeatureProvider.java
@@ -16,14 +16,17 @@
package com.android.settings.wifi.factory;
+import android.annotation.Nullable;
import android.content.Context;
import android.net.wifi.WifiManager;
+import android.util.Log;
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.WifiHotspotSpeedViewModel;
import com.android.settings.wifi.tether.WifiTetherViewModel;
import org.jetbrains.annotations.NotNull;
@@ -32,9 +35,11 @@ import org.jetbrains.annotations.NotNull;
* Wi-Fi Feature Provider
*/
public class WifiFeatureProvider {
+ private static final String TAG = "WifiFeatureProvider";
private final Context mAppContext;
private WifiManager mWifiManager;
+ private WifiVerboseLogging mWifiVerboseLogging;
private WifiHotspotRepository mWifiHotspotRepository;
public WifiFeatureProvider(@NonNull Context appContext) {
@@ -52,11 +57,22 @@ public class WifiFeatureProvider {
}
/**
- * Get WifiRepository
+ * Get WifiVerboseLogging
+ */
+ public WifiVerboseLogging getWifiVerboseLogging() {
+ if (mWifiVerboseLogging == null) {
+ mWifiVerboseLogging = new WifiVerboseLogging(mAppContext, getWifiManager());
+ }
+ return mWifiVerboseLogging;
+ }
+
+ /**
+ * Get WifiHotspotRepository
*/
public WifiHotspotRepository getWifiHotspotRepository() {
if (mWifiHotspotRepository == null) {
mWifiHotspotRepository = new WifiHotspotRepository(mAppContext, getWifiManager());
+ verboseLog(TAG, "getWifiHotspotRepository():" + mWifiHotspotRepository);
}
return mWifiHotspotRepository;
}
@@ -68,5 +84,26 @@ public class WifiFeatureProvider {
return new ViewModelProvider(owner).get(WifiTetherViewModel.class);
}
+ /**
+ * Get WifiHotspotSpeedViewModel
+ */
+ public WifiHotspotSpeedViewModel getWifiHotspotSpeedViewModel(
+ @NotNull ViewModelStoreOwner owner) {
+ WifiHotspotSpeedViewModel viewModel =
+ new ViewModelProvider(owner).get(WifiHotspotSpeedViewModel.class);
+ verboseLog(TAG, "getWifiHotspotSpeedViewModel():" + viewModel);
+ return viewModel;
+ }
+
+ /**
+ * Send a {@link Log#VERBOSE} log message.
+ *
+ * @param tag Used to identify the source of a log message. It usually identifies
+ * the class or activity where the log call occurs.
+ * @param msg The message you would like logged.
+ */
+ public void verboseLog(@Nullable String tag, @NonNull String msg) {
+ getWifiVerboseLogging().log(tag, msg);
+ }
}
diff --git a/src/com/android/settings/wifi/factory/WifiVerboseLogging.java b/src/com/android/settings/wifi/factory/WifiVerboseLogging.java
new file mode 100644
index 00000000000..2935ed49e74
--- /dev/null
+++ b/src/com/android/settings/wifi/factory/WifiVerboseLogging.java
@@ -0,0 +1,55 @@
+/*
+ * 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.factory;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.net.wifi.WifiManager;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+/**
+ * Wi-Fi Verbose Logging
+ */
+public class WifiVerboseLogging {
+ private static final String TAG = "WifiVerboseLogging";
+
+ protected final Context mAppContext;
+ protected final WifiManager mWifiManager;
+ protected final boolean mIsVerboseLoggingEnabled;
+
+ public WifiVerboseLogging(@NonNull Context appContext, @NonNull WifiManager wifiManager) {
+ mAppContext = appContext;
+ mWifiManager = wifiManager;
+ mIsVerboseLoggingEnabled = wifiManager.isVerboseLoggingEnabled();
+ Log.v(TAG, "isVerboseLoggingEnabled:" + mIsVerboseLoggingEnabled);
+ }
+
+ /**
+ * Send a {@link Log#VERBOSE} log message.
+ *
+ * @param tag Used to identify the source of a log message. It usually identifies
+ * the class or activity where the log call occurs.
+ * @param msg The message you would like logged.
+ */
+ public void log(@Nullable String tag, @NonNull String msg) {
+ if (mIsVerboseLoggingEnabled) {
+ Log.v(tag, msg);
+ }
+ }
+}
diff --git a/src/com/android/settings/wifi/repository/WifiHotspotRepository.java b/src/com/android/settings/wifi/repository/WifiHotspotRepository.java
index ee1ceea600e..ff6d8832ae1 100644
--- a/src/com/android/settings/wifi/repository/WifiHotspotRepository.java
+++ b/src/com/android/settings/wifi/repository/WifiHotspotRepository.java
@@ -32,7 +32,8 @@ import android.util.Log;
import androidx.annotation.NonNull;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
-import androidx.lifecycle.Transformations;
+
+import com.android.settings.overlay.FeatureFactory;
import java.util.HashMap;
import java.util.List;
@@ -45,7 +46,6 @@ import java.util.function.Consumer;
*/
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;
@@ -84,8 +84,12 @@ public class WifiHotspotRepository {
protected MutableLiveData mSpeedType;
protected Boolean mIsDualBand;
+ protected Boolean mIs5gBandSupported;
protected Boolean mIs5gAvailable;
+ protected MutableLiveData m5gAvailable;
+ protected Boolean mIs6gBandSupported;
protected Boolean mIs6gAvailable;
+ protected MutableLiveData m6gAvailable;
protected String mCurrentCountryCode;
protected ActiveCountryCodeChangedCallback mActiveCountryCodeChangedCallback;
@@ -140,6 +144,8 @@ public class WifiHotspotRepository {
* Refresh data from the SoftApConfiguration.
*/
public void refresh() {
+ update6gAvailable();
+ update5gAvailable();
updateSpeedType();
}
@@ -163,8 +169,9 @@ public class WifiHotspotRepository {
if (mSpeedType == null) {
mSpeedType = new MutableLiveData<>();
updateSpeedType();
+ log("getSpeedType():" + mSpeedType.getValue());
}
- return Transformations.distinctUntilChanged(mSpeedType);
+ return mSpeedType;
}
protected void updateSpeedType() {
@@ -177,7 +184,7 @@ public class WifiHotspotRepository {
return;
}
int keyBand = config.getBand();
- logd("updateSpeedType(), getBand():" + keyBand);
+ log("updateSpeedType(), getBand():" + keyBand);
if (!is5gAvailable()) {
keyBand &= ~BAND_5GHZ;
}
@@ -195,52 +202,172 @@ public class WifiHotspotRepository {
} else {
keyBand = 0;
}
- logd("updateSpeedType(), keyBand:" + keyBand);
+ log("updateSpeedType(), keyBand:" + keyBand);
mSpeedType.setValue(sSpeedMap.get(keyBand));
}
- protected boolean isDualBand() {
+ /**
+ * Sets SpeedType
+ *
+ * @param speedType the Wi-Fi hotspot speed type.
+ */
+ public void setSpeedType(int speedType) {
+ log("setSpeedType():" + speedType);
+ if (mSpeedType == null) {
+ getSpeedType();
+ }
+ if (speedType == mSpeedType.getValue()) {
+ Log.w(TAG, "setSpeedType() is no changed! mSpeedType:" + mSpeedType.getValue());
+ return;
+ }
+ SoftApConfiguration config = mWifiManager.getSoftApConfiguration();
+ if (config == null) {
+ mSpeedType.setValue(SPEED_UNKNOWN);
+ Log.e(TAG, "setSpeedType(), WifiManager#getSoftApConfiguration() return null!");
+ return;
+ }
+ SoftApConfiguration.Builder configBuilder = new SoftApConfiguration.Builder(config);
+ if (speedType == SPEED_6GHZ) {
+ log("setSpeedType(), setBand(BAND_2GHZ_5GHZ_6GHZ)");
+ configBuilder.setBand(BAND_2GHZ_5GHZ_6GHZ);
+ } else if (speedType == SPEED_5GHZ) {
+ log("setSpeedType(), setBand(BAND_2GHZ_5GHZ)");
+ configBuilder.setBand(BAND_2GHZ_5GHZ);
+ } else if (mIsDualBand) {
+ log("setSpeedType(), setBands(BAND_2GHZ + BAND_2GHZ_5GHZ)");
+ int[] bands = {BAND_2GHZ, BAND_2GHZ_5GHZ};
+ configBuilder.setBands(bands);
+ } else {
+ log("setSpeedType(), setBand(BAND_2GHZ)");
+ configBuilder.setBand(BAND_2GHZ);
+ }
+ setSoftApConfiguration(configBuilder.build());
+ }
+
+ /**
+ * Return whether Wi-Fi Dual Band is supported or not.
+ * @return {@code true} if Wi-Fi Dual Band is supported
+ */
+ public boolean isDualBand() {
if (mIsDualBand == null) {
mIsDualBand = mWifiManager.isBridgedApConcurrencySupported();
- logd("isDualBand():" + mIsDualBand);
+ log("isDualBand():" + mIsDualBand);
}
return mIsDualBand;
}
- protected boolean is5gAvailable() {
+ /**
+ * Return whether Wi-Fi 5 GHz band is supported or not.
+ * @return {@code true} if Wi-Fi 5 GHz Band is supported
+ */
+ public boolean is5GHzBandSupported() {
+ if (mIs5gBandSupported == null) {
+ mIs5gBandSupported = mWifiManager.is5GHzBandSupported();
+ log("is5GHzBandSupported():" + mIs5gBandSupported);
+ }
+ return mIs5gBandSupported;
+ }
+
+ /**
+ * Return whether Wi-Fi Hotspot 5 GHz band is available or not.
+ * @return {@code true} if Wi-Fi Hotspot 5 GHz Band is available
+ */
+ public 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);
+ // If Settings is unable to get available 5GHz SAP information, Wi-Fi Framework's
+ // proposal is to assume that 5GHz is available. (See b/272450463#comment16)
+ mIs5gAvailable = is5GHzBandSupported()
+ && isChannelAvailable(WifiScanner.WIFI_BAND_5_GHZ_WITH_DFS,
+ true /* defaultValue */);
+ log("is5gAvailable():" + mIs5gAvailable);
}
return mIs5gAvailable;
}
- protected boolean is6gAvailable() {
+ /**
+ * Gets is5gAvailable LiveData
+ */
+ public LiveData get5gAvailable() {
+ if (m5gAvailable == null) {
+ m5gAvailable = new MutableLiveData<>();
+ m5gAvailable.setValue(is5gAvailable());
+ }
+ return m5gAvailable;
+ }
+
+ protected void update5gAvailable() {
+ if (m5gAvailable != null) {
+ m5gAvailable.setValue(is5gAvailable());
+ }
+ }
+
+ /**
+ * Return whether Wi-Fi 6 GHz band is supported or not.
+ * @return {@code true} if Wi-Fi 6 GHz Band is supported
+ */
+ public boolean is6GHzBandSupported() {
+ if (mIs6gBandSupported == null) {
+ mIs6gBandSupported = mWifiManager.is6GHzBandSupported();
+ log("is6GHzBandSupported():" + mIs6gBandSupported);
+ }
+ return mIs6gBandSupported;
+ }
+
+ /**
+ * Return whether Wi-Fi Hotspot 6 GHz band is available or not.
+ * @return {@code true} if Wi-Fi Hotspot 6 GHz Band is available
+ */
+ public boolean is6gAvailable() {
if (mIs6gAvailable == null) {
- mIs6gAvailable = mWifiManager.is6GHzBandSupported()
- && isBandAvailable(WifiScanner.WIFI_BAND_6_GHZ);
- logd("is6gAvailable():" + mIs6gAvailable);
+ mIs6gAvailable = is6GHzBandSupported()
+ && isChannelAvailable(WifiScanner.WIFI_BAND_6_GHZ, false /* defaultValue */);
+ log("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}
+ * Gets is6gAvailable LiveData
*/
- protected boolean isBandAvailable(int band) {
- List channels = mWifiManager.getUsableChannels(band, OP_MODE_SAP);
- return (channels != null && channels.size() > 0);
+ public LiveData get6gAvailable() {
+ if (m6gAvailable == null) {
+ m6gAvailable = new MutableLiveData<>();
+ m6gAvailable.setValue(is6gAvailable());
+ }
+ return m6gAvailable;
+ }
+
+ protected void update6gAvailable() {
+ if (m6gAvailable != null) {
+ m6gAvailable.setValue(is6gAvailable());
+ }
+ }
+
+ /**
+ * Return whether the Hotspot channel 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}
+ * @param defaultValue returns the default value if WifiManager#getUsableChannels is
+ * unavailable to get the SAP information.
+ */
+ protected boolean isChannelAvailable(int band, boolean defaultValue) {
+ try {
+ List channels = mWifiManager.getUsableChannels(band, OP_MODE_SAP);
+ log("isChannelAvailable(), band:" + band + ", channels:" + channels);
+ return (channels != null && channels.size() > 0);
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "Querying usable SAP channels failed, band:" + band);
+ } catch (UnsupportedOperationException e) {
+ // This is expected on some hardware.
+ Log.e(TAG, "Querying usable SAP channels is unsupported, band:" + band);
+ }
+ return defaultValue;
}
protected void purgeRefreshData() {
- mIsDualBand = null;
mIs5gAvailable = null;
mIs6gAvailable = null;
}
@@ -249,7 +376,7 @@ public class WifiHotspotRepository {
if (mActiveCountryCodeChangedCallback != null) {
return;
}
- logd("startMonitorSoftApConfiguration()");
+ log("startMonitorSoftApConfiguration()");
mActiveCountryCodeChangedCallback = new ActiveCountryCodeChangedCallback();
mWifiManager.registerActiveCountryCodeChangedCallback(mAppContext.getMainExecutor(),
mActiveCountryCodeChangedCallback);
@@ -259,7 +386,7 @@ public class WifiHotspotRepository {
if (mActiveCountryCodeChangedCallback == null) {
return;
}
- logd("stopMonitorSoftApConfiguration()");
+ log("stopMonitorSoftApConfiguration()");
mWifiManager.unregisterActiveCountryCodeChangedCallback(mActiveCountryCodeChangedCallback);
mActiveCountryCodeChangedCallback = null;
}
@@ -268,7 +395,7 @@ public class WifiHotspotRepository {
WifiManager.ActiveCountryCodeChangedCallback {
@Override
public void onActiveCountryCodeChanged(String country) {
- logd("onActiveCountryCodeChanged(), country:" + country);
+ log("onActiveCountryCodeChanged(), country:" + country);
mCurrentCountryCode = country;
purgeRefreshData();
refresh();
@@ -276,16 +403,14 @@ public class WifiHotspotRepository {
@Override
public void onCountryCodeInactive() {
- logd("onCountryCodeInactive()");
+ log("onCountryCodeInactive()");
mCurrentCountryCode = null;
purgeRefreshData();
refresh();
}
}
- private static void logd(String msg) {
- if (DEBUG) {
- Log.d(TAG, msg);
- }
+ private void log(String msg) {
+ FeatureFactory.getFactory(mAppContext).getWifiFeatureProvider().verboseLog(TAG, msg);
}
}
diff --git a/src/com/android/settings/wifi/tether/WifiHotspotSpeedSettings.java b/src/com/android/settings/wifi/tether/WifiHotspotSpeedSettings.java
new file mode 100644
index 00000000000..467d3944681
--- /dev/null
+++ b/src/com/android/settings/wifi/tether/WifiHotspotSpeedSettings.java
@@ -0,0 +1,132 @@
+/*
+ * 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 android.app.settings.SettingsEnums;
+import android.os.Bundle;
+
+import com.android.settings.R;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settingslib.widget.SelectorWithWidgetPreference;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Wi-Fi Hotspot Speed & compatibility Settings
+ */
+public class WifiHotspotSpeedSettings extends DashboardFragment implements
+ SelectorWithWidgetPreference.OnClickListener {
+
+ private static final String TAG = "WifiHotspotSpeedSettings";
+
+ protected static final String KEY_SPEED_2GHZ = "wifi_hotspot_speed_2g";
+ protected static final String KEY_SPEED_5GHZ = "wifi_hotspot_speed_5g";
+ protected static final String KEY_SPEED_2GHZ_5GHZ = "wifi_hotspot_speed_2g_5g";
+ protected static final String KEY_SPEED_6GHZ = "wifi_hotspot_speed_6g";
+ protected static Map sSpeedKeyMap = new HashMap<>();
+
+ static {
+ sSpeedKeyMap.put(KEY_SPEED_2GHZ, SPEED_2GHZ);
+ sSpeedKeyMap.put(KEY_SPEED_5GHZ, SPEED_5GHZ);
+ sSpeedKeyMap.put(KEY_SPEED_2GHZ_5GHZ, SPEED_2GHZ_5GHZ);
+ sSpeedKeyMap.put(KEY_SPEED_6GHZ, SPEED_6GHZ);
+ }
+
+ protected WifiHotspotSpeedViewModel mWifiHotspotSpeedViewModel;
+ protected Map mSpeedPreferenceMap = new HashMap<>();
+
+ @Override
+ protected int getPreferenceScreenResId() {
+ return R.xml.wifi_hotspot_speed;
+ }
+
+ @Override
+ protected String getLogTag() {
+ return TAG;
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return SettingsEnums.WIFI_TETHER_SETTINGS;
+ }
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ loadPreferences();
+ mWifiHotspotSpeedViewModel = FeatureFactory.getFactory(getContext())
+ .getWifiFeatureProvider().getWifiHotspotSpeedViewModel(this);
+ onSpeedInfoMapDataChanged(mWifiHotspotSpeedViewModel.getSpeedInfoMapData().getValue());
+ mWifiHotspotSpeedViewModel.getSpeedInfoMapData()
+ .observe(this, this::onSpeedInfoMapDataChanged);
+ }
+
+ protected void loadPreferences() {
+ for (Map.Entry entry : sSpeedKeyMap.entrySet()) {
+ SelectorWithWidgetPreference preference = findPreference(entry.getKey());
+ if (preference != null) {
+ preference.setOnClickListener(this);
+ mSpeedPreferenceMap.put(entry.getValue(), preference);
+ }
+ }
+ }
+
+ protected void onSpeedInfoMapDataChanged(
+ Map speedInfoMap) {
+ log("onSpeedViewDataChanged(), speedInfoMap:" + speedInfoMap);
+ for (Map.Entry entry :
+ mSpeedPreferenceMap.entrySet()) {
+ WifiHotspotSpeedViewModel.SpeedInfo speedInfo = speedInfoMap.get(entry.getKey());
+ if (speedInfo == null) {
+ continue;
+ }
+ SelectorWithWidgetPreference radioButton = entry.getValue();
+ if (radioButton == null) {
+ continue;
+ }
+ if (radioButton.isChecked() != speedInfo.mIsChecked) {
+ radioButton.setChecked(speedInfo.mIsChecked);
+ }
+ if (radioButton.isEnabled() != speedInfo.mIsEnabled) {
+ radioButton.setEnabled(speedInfo.mIsEnabled);
+ }
+ if (radioButton.isVisible() != speedInfo.mIsVisible) {
+ radioButton.setVisible(speedInfo.mIsVisible);
+ }
+ }
+ }
+
+ @Override
+ public void onRadioButtonClicked(SelectorWithWidgetPreference emiter) {
+ String key = emiter.getKey();
+ log("onRadioButtonClicked(), key:" + key);
+ if (sSpeedKeyMap.containsKey(key)) {
+ mWifiHotspotSpeedViewModel.setSpeedType(sSpeedKeyMap.get(key));
+ }
+ }
+
+ private void log(String msg) {
+ FeatureFactory.getFactory(getContext()).getWifiFeatureProvider().verboseLog(TAG, msg);
+ }
+}
diff --git a/src/com/android/settings/wifi/tether/WifiHotspotSpeedViewModel.java b/src/com/android/settings/wifi/tether/WifiHotspotSpeedViewModel.java
new file mode 100644
index 00000000000..c30174e7614
--- /dev/null
+++ b/src/com/android/settings/wifi/tether/WifiHotspotSpeedViewModel.java
@@ -0,0 +1,160 @@
+/*
+ * 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 android.app.Application;
+
+import androidx.lifecycle.AndroidViewModel;
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.MutableLiveData;
+import androidx.lifecycle.Observer;
+
+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 Speed View Model
+ */
+public class WifiHotspotSpeedViewModel extends AndroidViewModel {
+ private static final String TAG = "WifiHotspotSpeedViewModel";
+
+ protected final WifiHotspotRepository mWifiHotspotRepository;
+ protected Map mSpeedInfoMap = new HashMap<>();
+ protected MutableLiveData