Merge "Use updated lockscreen validation API in Settings." into udc-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index d82fc94..dc519e9 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -3073,7 +3073,8 @@
             android:name="Settings$PowerUsageSummaryActivity"
             android:label="@string/power_usage_summary_title"
             android:exported="true"
-            android:icon="@drawable/ic_homepage_battery">
+            android:icon="@drawable/ic_homepage_battery"
+            android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize">
             <intent-filter android:priority="1">
                 <action android:name="android.intent.action.POWER_USAGE_SUMMARY" />
                 <category android:name="android.intent.category.DEFAULT" />
diff --git a/res/values/config.xml b/res/values/config.xml
index 43643d3..ef786be 100755
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -363,6 +363,9 @@
     <!-- Whether Wi-Fi hotspot settings should be shown or not. -->
     <bool name="config_show_wifi_hotspot_settings">true</bool>
 
+    <!-- Whether Wi-Fi hotspot speed should be shown or not. -->
+    <bool name="config_show_wifi_hotspot_speed">false</bool>
+
     <!-- Whether toggle_airplane is available or not. -->
     <bool name="config_show_toggle_airplane">true</bool>
 
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 69d2512..a79b1d4 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -2015,6 +2015,16 @@
     <string name="wifi_hotspot_maximize_compatibility_single_ap_summary">Helps other devices find this hotspot. Reduces hotspot connection speed.</string>
     <!-- Summary for the toggle to show the maximize compatibility warning message in dual AP device [CHAR LIMIT=NONE]-->
     <string name="wifi_hotspot_maximize_compatibility_dual_ap_summary">Helps other devices find this hotspot. Increases battery usage.</string>
+    <!-- Title for Wifi hotspot speed [CHAR LIMIT=NONE]-->
+    <string name="wifi_hotspot_speed_title">Speed &amp; compatibility</string>
+    <!-- Summary for Wifi hotspot speed to 2.4 GHz band [CHAR LIMIT=NONE]-->
+    <string name="wifi_hotspot_speed_2g_summary">2.4 GHz / Any device can connect</string>
+    <!-- Summary for Wifi hotspot speed to 5 GHz band [CHAR LIMIT=NONE]-->
+    <string name="wifi_hotspot_speed_5g_summary">5 GHz / Most devices can connect</string>
+    <!-- Summary for Wifi hotspot speed to 6 GHz band [CHAR LIMIT=NONE]-->
+    <string name="wifi_hotspot_speed_6g_summary">6 GHz / Few devices can connect</string>
+    <!-- Summary for Wifi hotspot speed to 6 GHz band [CHAR LIMIT=NONE]-->
+    <string name="wifi_hotspot_speed_2g_and_5g_summary">2.4 and 5 GHz / Any device can connect</string>
 
     <!-- Summary text when turning hotspot on -->
     <string name="wifi_tether_starting">Turning hotspot on\u2026</string>
@@ -6798,6 +6808,10 @@
     <string name="cloned_app_creation_summary">Creating&#8230;</string>
     <!-- Summary text after an app is cloned [CHAR LIMIT=40] -->
     <string name="cloned_app_created_summary">Cloned</string>
+    <!-- Summary text shown in toast when app is being cloned [CHAR LIMIT=40] -->
+    <string name="cloned_app_creation_toast_summary">Creating <xliff:g id="package_label">%1$s</xliff:g> clone</string>
+    <!-- Summary text shown in toast after app is successfully cloned [CHAR LIMIT=40] -->
+    <string name="cloned_app_created_toast_summary">Created <xliff:g id="package_label">%1$s</xliff:g> clone</string>
     <!-- Summary text for system preference title, showing important setting items under system setting [CHAR LIMIT=NONE]-->
     <string name="system_dashboard_summary">Languages, gestures, time, backup</string>
     <!-- Summary text for language preference title, showing important setting items under language setting [CHAR LIMIT=NONE]-->
diff --git a/res/xml/wifi_tether_settings.xml b/res/xml/wifi_tether_settings.xml
index 21f347b..1cd5f48 100644
--- a/res/xml/wifi_tether_settings.xml
+++ b/res/xml/wifi_tether_settings.xml
@@ -45,4 +45,10 @@
     <SwitchPreference
         android:key="wifi_tether_maximize_compatibility"
         android:title="@string/wifi_hotspot_maximize_compatibility"/>
+
+    <Preference
+        android:key="wifi_hotspot_speed"
+        android:title="@string/wifi_hotspot_speed_title"
+        android:summary="@string/summary_placeholder"
+        settings:isPreferenceVisible="@bool/config_show_wifi_hotspot_speed"/>
 </PreferenceScreen>
diff --git a/src/com/android/settings/applications/ProcessStatsUi.java b/src/com/android/settings/applications/ProcessStatsUi.java
index f49d638..ab334a8 100644
--- a/src/com/android/settings/applications/ProcessStatsUi.java
+++ b/src/com/android/settings/applications/ProcessStatsUi.java
@@ -137,11 +137,6 @@
             ProcessStats.STATE_TOP
     };
 
-    public static final int[] CACHED_PROC_STATES = new int[] {
-            ProcessStats.STATE_CACHED_ACTIVITY, ProcessStats.STATE_CACHED_ACTIVITY_CLIENT,
-            ProcessStats.STATE_CACHED_EMPTY
-    };
-
     public static String makeDuration(long time) {
         StringBuilder sb = new StringBuilder(32);
         TimeUtils.formatDuration(time, sb);
diff --git a/src/com/android/settings/connecteddevice/stylus/StylusDeviceUpdater.java b/src/com/android/settings/connecteddevice/stylus/StylusDeviceUpdater.java
index 46ef3fb..da6e178 100644
--- a/src/com/android/settings/connecteddevice/stylus/StylusDeviceUpdater.java
+++ b/src/com/android/settings/connecteddevice/stylus/StylusDeviceUpdater.java
@@ -22,7 +22,6 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
-import android.os.SystemClock;
 import android.util.Log;
 import android.view.InputDevice;
 
@@ -57,11 +56,11 @@
     private final InputManager mInputManager;
     private final MetricsFeatureProvider mMetricsFeatureProvider;
 
-    private long mLastUsiSeenTime = 0;
     private Context mContext;
 
     @VisibleForTesting
     Integer mLastDetectedUsiId;
+    BatteryState mLastBatteryState;
 
     @VisibleForTesting
     Preference mUsiPreference;
@@ -75,7 +74,6 @@
         mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
         mContext = context;
         mInputManager = context.getSystemService(InputManager.class);
-
     }
 
     /**
@@ -132,13 +130,8 @@
     @Override
     public void onBatteryStateChanged(int deviceId, long eventTimeMillis,
             @NonNull BatteryState batteryState) {
-        if (batteryState.isPresent()) {
-            mLastUsiSeenTime = eventTimeMillis;
-            mLastDetectedUsiId = deviceId;
-        } else {
-            mLastUsiSeenTime = -1;
-            mLastDetectedUsiId = null;
-        }
+        mLastBatteryState = batteryState;
+        mLastDetectedUsiId = deviceId;
         forceUpdate();
     }
 
@@ -184,7 +177,7 @@
     }
 
     private boolean shouldShowUsiPreference() {
-        return isUsiConnectionValid() && !hasConnectedBluetoothStylusDevice();
+        return isUsiBatteryValid() && !hasConnectedBluetoothStylusDevice();
     }
 
     @VisibleForTesting
@@ -206,11 +199,9 @@
     }
 
     @VisibleForTesting
-    boolean isUsiConnectionValid() {
-        // battery listener uses uptimeMillis as its eventTime
-        long currentTime = SystemClock.uptimeMillis();
-        long usiValidityDuration = 60 * 60 * 1000; // 1 hour
-        return mLastUsiSeenTime > 0 && currentTime - usiValidityDuration <= mLastUsiSeenTime;
+    boolean isUsiBatteryValid() {
+        return mLastBatteryState != null
+                && mLastBatteryState.isPresent() && mLastBatteryState.getCapacity() > 0f;
     }
 
     private void launchDeviceDetails() {
diff --git a/src/com/android/settings/search/SearchFeatureProvider.java b/src/com/android/settings/search/SearchFeatureProvider.java
index b14a4d7..cd096ec 100644
--- a/src/com/android/settings/search/SearchFeatureProvider.java
+++ b/src/com/android/settings/search/SearchFeatureProvider.java
@@ -126,16 +126,24 @@
                 true /* finishSecondaryWithPrimary */,
                 false /* clearTop */);
 
-        toolbar.setOnClickListener(tb -> {
-            FeatureFactory.getFactory(context).getSlicesFeatureProvider()
-                    .indexSliceDataAsync(context);
+        toolbar.setOnClickListener(tb -> startSearchActivity(context, activity, pageId, intent));
 
-            FeatureFactory.getFactory(context).getMetricsFeatureProvider()
-                    .logSettingsTileClick(KEY_HOMEPAGE_SEARCH_BAR, pageId);
+        toolbar.setHandwritingDelegatorCallback(
+                () -> startSearchActivity(context, activity, pageId, intent));
+        toolbar.setAllowedHandwritingDelegatePackage(intent.getPackage());
+    }
 
-            final Bundle bundle = ActivityOptions.makeSceneTransitionAnimation(activity).toBundle();
-            activity.startActivity(intent, bundle);
-        });
+    /** Start the search activity. */
+    private static void startSearchActivity(
+            Context context, FragmentActivity activity, int pageId, Intent intent) {
+        FeatureFactory.getFactory(context).getSlicesFeatureProvider()
+                .indexSliceDataAsync(context);
+
+        FeatureFactory.getFactory(context).getMetricsFeatureProvider()
+                .logSettingsTileClick(KEY_HOMEPAGE_SEARCH_BAR, pageId);
+
+        final Bundle bundle = ActivityOptions.makeSceneTransitionAnimation(activity).toBundle();
+        activity.startActivity(intent, bundle);
     }
 
     Intent buildSearchIntent(Context context, int pageId);
diff --git a/src/com/android/settings/spa/app/appinfo/AppCreateButton.kt b/src/com/android/settings/spa/app/appinfo/AppCreateButton.kt
index 1414626..088680d 100644
--- a/src/com/android/settings/spa/app/appinfo/AppCreateButton.kt
+++ b/src/com/android/settings/spa/app/appinfo/AppCreateButton.kt
@@ -32,6 +32,7 @@
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
+import android.widget.Toast;
 
 class AppCreateButton(packageInfoPresenter: PackageInfoPresenter) {
     private val context = packageInfoPresenter.context
@@ -55,10 +56,16 @@
             val cloneBackend = CloneBackend.getInstance(context)
             FeatureFactory.getFactory(context).metricsFeatureProvider.action(context,
                     SettingsEnums.ACTION_CREATE_CLONE_APP)
+            val appLabel = app.loadLabel(context.packageManager)
+            Toast.makeText(context, context.getString(R.string.cloned_app_creation_toast_summary,
+                appLabel),Toast.LENGTH_SHORT).show()
             coroutineScope.launch {
                 enabledState.value = false
                 val result = installCloneApp(app, cloneBackend)
                 if (result == CloneBackend.SUCCESS) {
+                    Toast.makeText(context,
+                        context.getString(R.string.cloned_app_created_toast_summary, appLabel),
+                            Toast.LENGTH_SHORT).show()
                     navController.navigate(getRoute(app.packageName, cloneBackend.cloneUserId),
                             /* popUpCurrent*/ true)
                 } else {
diff --git a/src/com/android/settings/wifi/factory/WifiFeatureProvider.java b/src/com/android/settings/wifi/factory/WifiFeatureProvider.java
index 2f5f3ea..433ff0c 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.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 @@
         }
         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 b8a25dc..ee1ceea 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 @@
  * 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<Integer, Integer> 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 @@
     protected String mLastPassword;
     protected LastPasswordListener mLastPasswordListener = new LastPasswordListener();
 
+    protected MutableLiveData<Integer> 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 @@
         //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<Integer> 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<WifiAvailableChannel> 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 47dba76..3a3691a 100644
--- a/src/com/android/settings/wifi/tether/WifiTetherSettings.java
+++ b/src/com/android/settings/wifi/tether/WifiTetherSettings.java
@@ -34,11 +34,13 @@
 
 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 @@
     @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 @@
     @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 @@
 
         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 @@
             // Handle the initial state after register the receiver.
             updateDisplayWithNewConfig();
         }
+        mWifiTetherViewModel.refresh();
     }
 
     @Override
@@ -189,6 +206,9 @@
         }
     }
 
+    protected void onSpeedSummaryChanged(Integer summaryResId) {
+        mWifiHotspotSpeed.setSummary(summaryResId);
+    }
 
     @Override
     protected int getPreferenceScreenResId() {
@@ -228,7 +248,7 @@
             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 0000000..4abca02
--- /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<Integer, Integer> 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<Integer> 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<Integer> 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/connecteddevice/stylus/StylusDeviceUpdaterTest.java b/tests/robotests/src/com/android/settings/connecteddevice/stylus/StylusDeviceUpdaterTest.java
index 10f3727..7fb17e2 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/stylus/StylusDeviceUpdaterTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/stylus/StylusDeviceUpdaterTest.java
@@ -127,7 +127,7 @@
     @Test
     public void click_usiPreference_launchUsiDetailsPage() {
         doReturn(mSettingsActivity).when(mDashboardFragment).getContext();
-        doReturn(true).when(mStylusDeviceUpdater).isUsiConnectionValid();
+        doReturn(true).when(mStylusDeviceUpdater).isUsiBatteryValid();
         doReturn(false).when(mStylusDeviceUpdater).hasConnectedBluetoothStylusDevice();
         mStylusDeviceUpdater.forceUpdate();
         mStylusDeviceUpdater.mLastDetectedUsiId = 1;
@@ -144,7 +144,7 @@
 
     @Test
     public void forceUpdate_addsUsiPreference_validUsiDevice() {
-        doReturn(true).when(mStylusDeviceUpdater).isUsiConnectionValid();
+        doReturn(true).when(mStylusDeviceUpdater).isUsiBatteryValid();
         doReturn(false).when(mStylusDeviceUpdater).hasConnectedBluetoothStylusDevice();
 
         mStylusDeviceUpdater.forceUpdate();
@@ -154,7 +154,7 @@
 
     @Test
     public void forceUpdate_doesNotAddPreference_invalidUsiDevice() {
-        doReturn(false).when(mStylusDeviceUpdater).isUsiConnectionValid();
+        doReturn(false).when(mStylusDeviceUpdater).isUsiBatteryValid();
         doReturn(false).when(mStylusDeviceUpdater).hasConnectedBluetoothStylusDevice();
 
         mStylusDeviceUpdater.forceUpdate();
@@ -164,12 +164,12 @@
 
     @Test
     public void forceUpdate_removesUsiPreference_existingPreference_invalidUsiDevice() {
-        doReturn(true).when(mStylusDeviceUpdater).isUsiConnectionValid();
+        doReturn(true).when(mStylusDeviceUpdater).isUsiBatteryValid();
         doReturn(false).when(mStylusDeviceUpdater).hasConnectedBluetoothStylusDevice();
 
         mStylusDeviceUpdater.forceUpdate();
 
-        doReturn(false).when(mStylusDeviceUpdater).isUsiConnectionValid();
+        doReturn(false).when(mStylusDeviceUpdater).isUsiBatteryValid();
         mStylusDeviceUpdater.forceUpdate();
 
         assertThat(mStylusDeviceUpdater.mUsiPreference).isNull();
@@ -177,7 +177,7 @@
 
     @Test
     public void forceUpdate_doesNotAddUsiPreference_bluetoothStylusConnected() {
-        doReturn(true).when(mStylusDeviceUpdater).isUsiConnectionValid();
+        doReturn(true).when(mStylusDeviceUpdater).isUsiBatteryValid();
         doReturn(true).when(mStylusDeviceUpdater).hasConnectedBluetoothStylusDevice();
 
         mStylusDeviceUpdater.forceUpdate();
@@ -187,7 +187,7 @@
 
     @Test
     public void forceUpdate_addsUsiPreference_bluetoothStylusDisconnected() {
-        doReturn(true).when(mStylusDeviceUpdater).isUsiConnectionValid();
+        doReturn(true).when(mStylusDeviceUpdater).isUsiBatteryValid();
         doReturn(true).when(mStylusDeviceUpdater).hasConnectedBluetoothStylusDevice();
         mStylusDeviceUpdater.forceUpdate();
 
@@ -199,7 +199,7 @@
 
     @Test
     public void forceUpdate_removesUsiPreference_existingPreference_bluetoothStylusConnected() {
-        doReturn(true).when(mStylusDeviceUpdater).isUsiConnectionValid();
+        doReturn(true).when(mStylusDeviceUpdater).isUsiBatteryValid();
         doReturn(false).when(mStylusDeviceUpdater).hasConnectedBluetoothStylusDevice();
         mStylusDeviceUpdater.forceUpdate();
         doReturn(true).when(mStylusDeviceUpdater).hasConnectedBluetoothStylusDevice();
@@ -218,7 +218,7 @@
         mStylusDeviceUpdater.onBatteryStateChanged(1, SystemClock.uptimeMillis(),
                 batteryState);
 
-        assertThat(mStylusDeviceUpdater.isUsiConnectionValid()).isTrue();
+        assertThat(mStylusDeviceUpdater.isUsiBatteryValid()).isTrue();
     }
 
     @Test
@@ -230,19 +230,7 @@
         mStylusDeviceUpdater.onBatteryStateChanged(1, SystemClock.uptimeMillis(),
                 batteryState);
 
-        assertThat(mStylusDeviceUpdater.isUsiConnectionValid()).isFalse();
-    }
-
-    @Test
-    public void onBatteryStateChanged_ddetectsInvalidUsi_staleBatteryEventTime() {
-        doReturn(false).when(mStylusDeviceUpdater).hasConnectedBluetoothStylusDevice();
-        BatteryState batteryState = mock(BatteryState.class);
-        doReturn(true).when(batteryState).isPresent();
-        doReturn(0.5f).when(batteryState).getCapacity();
-
-        mStylusDeviceUpdater.onBatteryStateChanged(1, 0, batteryState);
-
-        assertThat(mStylusDeviceUpdater.isUsiConnectionValid()).isFalse();
+        assertThat(mStylusDeviceUpdater.isUsiBatteryValid()).isFalse();
     }
 
     @Test
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 7f8a06d..582f792 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.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.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 @@
     private PreferenceScreen mPreferenceScreen;
     @Mock
     private TextView mEmptyTextView;
+    @Mock
+    WifiTetherViewModel mWifiTetherViewModel;
+    @Mock
+    WifiHotspotRepository mWifiHotspotRepository;
 
     private WifiTetherSettings mWifiTetherSettings;
 
@@ -106,6 +114,11 @@
         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);
     }
 
@@ -143,6 +156,16 @@
     }
 
     @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))
                 .isNotEmpty();
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 58a9d1c..52f02f5 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.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 @@
 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 @@
     Context mContext = ApplicationProvider.getApplicationContext();
     @Mock
     WifiManager mWifiManager;
+    @Mock
+    MutableLiveData<Integer> mSpeedType;
 
     WifiHotspotRepository mWifiHotspotRepository;
     SoftApConfiguration mSoftApConfiguration;
@@ -60,6 +77,10 @@
     @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 @@
         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 0000000..6724dd5
--- /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<Integer> 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();
+    }
+}