diff options
| author | 2024-02-27 11:56:56 +0800 | |
|---|---|---|
| committer | 2024-02-29 07:24:21 +0000 | |
| commit | ef6c5ea0fb733a0a8f1170d7cdb19e1119e72f08 (patch) | |
| tree | c85b3c81ccfd1910608702073831d7272bef59e0 | |
| parent | f909a8f54159cc6db8cc1e7558543dedc28a22fa (diff) | |
Change WifiUtils.java into kotlin.
Test: Visual Test
Fix: 327067271
Change-Id: Ieee2fe30080185fce458b1d331f1baf288c012c3
| -rw-r--r-- | packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java | 447 | ||||
| -rw-r--r-- | packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.kt | 462 |
2 files changed, 462 insertions, 447 deletions
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java deleted file mode 100644 index 69f83a4dfa3c..000000000000 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java +++ /dev/null @@ -1,447 +0,0 @@ -/* - * Copyright (C) 2017 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.settingslib.wifi; - -import static android.net.wifi.WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLED; -import static android.net.wifi.WifiConfiguration.NetworkSelectionStatus.getMaxNetworkSelectionDisableReason; - -import static com.android.settingslib.flags.Flags.newStatusBarIcons; - -import android.content.Context; -import android.content.Intent; -import android.graphics.drawable.Drawable; -import android.icu.text.MessageFormat; -import android.net.wifi.ScanResult; -import android.net.wifi.WifiConfiguration; -import android.net.wifi.WifiConfiguration.NetworkSelectionStatus; -import android.net.wifi.WifiInfo; -import android.net.wifi.sharedconnectivity.app.NetworkProviderInfo; -import android.os.Bundle; -import android.os.SystemClock; -import android.util.Log; - -import androidx.annotation.VisibleForTesting; - -import com.android.settingslib.R; - -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; - -public class WifiUtils { - - private static final String TAG = "WifiUtils"; - - private static final int INVALID_RSSI = -127; - - /** - * The intent action shows Wi-Fi dialog to connect Wi-Fi network. - * <p> - * Input: The calling package should put the chosen - * com.android.wifitrackerlib.WifiEntry#getKey() to a string extra in the request bundle into - * the {@link #EXTRA_CHOSEN_WIFI_ENTRY_KEY}. - * <p> - * Output: Nothing. - */ - @VisibleForTesting - static final String ACTION_WIFI_DIALOG = "com.android.settings.WIFI_DIALOG"; - - /** - * Specify a key that indicates the WifiEntry to be configured. - */ - @VisibleForTesting - static final String EXTRA_CHOSEN_WIFI_ENTRY_KEY = "key_chosen_wifientry_key"; - - /** - * The lookup key for a boolean that indicates whether a chosen WifiEntry request to connect to. - * {@code true} means a chosen WifiEntry request to connect to. - */ - @VisibleForTesting - static final String EXTRA_CONNECT_FOR_CALLER = "connect_for_caller"; - - /** - * The intent action shows network details settings to allow configuration of Wi-Fi. - * <p> - * In some cases, a matching Activity may not exist, so ensure you - * safeguard against this. - * <p> - * Input: The calling package should put the chosen - * com.android.wifitrackerlib.WifiEntry#getKey() to a string extra in the request bundle into - * the {@link #KEY_CHOSEN_WIFIENTRY_KEY}. - * <p> - * Output: Nothing. - */ - public static final String ACTION_WIFI_DETAILS_SETTINGS = - "android.settings.WIFI_DETAILS_SETTINGS"; - public static final String KEY_CHOSEN_WIFIENTRY_KEY = "key_chosen_wifientry_key"; - public static final String EXTRA_SHOW_FRAGMENT_ARGUMENTS = ":settings:show_fragment_args"; - - static final int[] WIFI_PIE = getIconsBasedOnFlag(); - - private static int[] getIconsBasedOnFlag() { - if (newStatusBarIcons()) { - return new int[] { - R.drawable.ic_wifi_0, - R.drawable.ic_wifi_1, - R.drawable.ic_wifi_2, - R.drawable.ic_wifi_3, - R.drawable.ic_wifi_4 - }; - } else { - return new int[] { - com.android.internal.R.drawable.ic_wifi_signal_0, - com.android.internal.R.drawable.ic_wifi_signal_1, - com.android.internal.R.drawable.ic_wifi_signal_2, - com.android.internal.R.drawable.ic_wifi_signal_3, - com.android.internal.R.drawable.ic_wifi_signal_4 - }; - } - } - - static final int[] NO_INTERNET_WIFI_PIE = getErrorIconsBasedOnFlag(); - - private static int [] getErrorIconsBasedOnFlag() { - if (newStatusBarIcons()) { - return new int[] { - R.drawable.ic_wifi_0_error, - R.drawable.ic_wifi_1_error, - R.drawable.ic_wifi_2_error, - R.drawable.ic_wifi_3_error, - R.drawable.ic_wifi_4_error - }; - } else { - return new int[] { - R.drawable.ic_no_internet_wifi_signal_0, - R.drawable.ic_no_internet_wifi_signal_1, - R.drawable.ic_no_internet_wifi_signal_2, - R.drawable.ic_no_internet_wifi_signal_3, - R.drawable.ic_no_internet_wifi_signal_4 - }; - } - } - - public static String buildLoggingSummary(AccessPoint accessPoint, WifiConfiguration config) { - final StringBuilder summary = new StringBuilder(); - final WifiInfo info = accessPoint.getInfo(); - // Add RSSI/band information for this config, what was seen up to 6 seconds ago - // verbose WiFi Logging is only turned on thru developers settings - if (accessPoint.isActive() && info != null) { - summary.append(" f=" + Integer.toString(info.getFrequency())); - } - summary.append(" " + getVisibilityStatus(accessPoint)); - if (config != null - && (config.getNetworkSelectionStatus().getNetworkSelectionStatus() - != NETWORK_SELECTION_ENABLED)) { - summary.append(" (" + config.getNetworkSelectionStatus().getNetworkStatusString()); - if (config.getNetworkSelectionStatus().getDisableTime() > 0) { - long now = System.currentTimeMillis(); - long diff = (now - config.getNetworkSelectionStatus().getDisableTime()) / 1000; - long sec = diff % 60; //seconds - long min = (diff / 60) % 60; //minutes - long hour = (min / 60) % 60; //hours - summary.append(", "); - if (hour > 0) summary.append(Long.toString(hour) + "h "); - summary.append(Long.toString(min) + "m "); - summary.append(Long.toString(sec) + "s "); - } - summary.append(")"); - } - - if (config != null) { - NetworkSelectionStatus networkStatus = config.getNetworkSelectionStatus(); - for (int reason = 0; reason <= getMaxNetworkSelectionDisableReason(); reason++) { - if (networkStatus.getDisableReasonCounter(reason) != 0) { - summary.append(" ") - .append(NetworkSelectionStatus - .getNetworkSelectionDisableReasonString(reason)) - .append("=") - .append(networkStatus.getDisableReasonCounter(reason)); - } - } - } - - return summary.toString(); - } - - /** - * Returns the visibility status of the WifiConfiguration. - * - * @return autojoin debugging information - * TODO: use a string formatter - * ["rssi 5Ghz", "num results on 5GHz" / "rssi 5Ghz", "num results on 5GHz"] - * For instance [-40,5/-30,2] - */ - @VisibleForTesting - static String getVisibilityStatus(AccessPoint accessPoint) { - final WifiInfo info = accessPoint.getInfo(); - StringBuilder visibility = new StringBuilder(); - StringBuilder scans24GHz = new StringBuilder(); - StringBuilder scans5GHz = new StringBuilder(); - StringBuilder scans60GHz = new StringBuilder(); - String bssid = null; - - if (accessPoint.isActive() && info != null) { - bssid = info.getBSSID(); - if (bssid != null) { - visibility.append(" ").append(bssid); - } - visibility.append(" standard = ").append(info.getWifiStandard()); - visibility.append(" rssi=").append(info.getRssi()); - visibility.append(" "); - visibility.append(" score=").append(info.getScore()); - if (accessPoint.getSpeed() != AccessPoint.Speed.NONE) { - visibility.append(" speed=").append(accessPoint.getSpeedLabel()); - } - visibility.append(String.format(" tx=%.1f,", info.getSuccessfulTxPacketsPerSecond())); - visibility.append(String.format("%.1f,", info.getRetriedTxPacketsPerSecond())); - visibility.append(String.format("%.1f ", info.getLostTxPacketsPerSecond())); - visibility.append(String.format("rx=%.1f", info.getSuccessfulRxPacketsPerSecond())); - } - - int maxRssi5 = INVALID_RSSI; - int maxRssi24 = INVALID_RSSI; - int maxRssi60 = INVALID_RSSI; - final int maxDisplayedScans = 4; - int num5 = 0; // number of scanned BSSID on 5GHz band - int num24 = 0; // number of scanned BSSID on 2.4Ghz band - int num60 = 0; // number of scanned BSSID on 60Ghz band - int numBlockListed = 0; - - // TODO: sort list by RSSI or age - long nowMs = SystemClock.elapsedRealtime(); - for (ScanResult result : accessPoint.getScanResults()) { - if (result == null) { - continue; - } - if (result.frequency >= AccessPoint.LOWER_FREQ_5GHZ - && result.frequency <= AccessPoint.HIGHER_FREQ_5GHZ) { - // Strictly speaking: [4915, 5825] - num5++; - - if (result.level > maxRssi5) { - maxRssi5 = result.level; - } - if (num5 <= maxDisplayedScans) { - scans5GHz.append( - verboseScanResultSummary(accessPoint, result, bssid, - nowMs)); - } - } else if (result.frequency >= AccessPoint.LOWER_FREQ_24GHZ - && result.frequency <= AccessPoint.HIGHER_FREQ_24GHZ) { - // Strictly speaking: [2412, 2482] - num24++; - - if (result.level > maxRssi24) { - maxRssi24 = result.level; - } - if (num24 <= maxDisplayedScans) { - scans24GHz.append( - verboseScanResultSummary(accessPoint, result, bssid, - nowMs)); - } - } else if (result.frequency >= AccessPoint.LOWER_FREQ_60GHZ - && result.frequency <= AccessPoint.HIGHER_FREQ_60GHZ) { - // Strictly speaking: [60000, 61000] - num60++; - - if (result.level > maxRssi60) { - maxRssi60 = result.level; - } - if (num60 <= maxDisplayedScans) { - scans60GHz.append( - verboseScanResultSummary(accessPoint, result, bssid, - nowMs)); - } - } - } - visibility.append(" ["); - if (num24 > 0) { - visibility.append("(").append(num24).append(")"); - if (num24 > maxDisplayedScans) { - visibility.append("max=").append(maxRssi24).append(","); - } - visibility.append(scans24GHz.toString()); - } - visibility.append(";"); - if (num5 > 0) { - visibility.append("(").append(num5).append(")"); - if (num5 > maxDisplayedScans) { - visibility.append("max=").append(maxRssi5).append(","); - } - visibility.append(scans5GHz.toString()); - } - visibility.append(";"); - if (num60 > 0) { - visibility.append("(").append(num60).append(")"); - if (num60 > maxDisplayedScans) { - visibility.append("max=").append(maxRssi60).append(","); - } - visibility.append(scans60GHz.toString()); - } - if (numBlockListed > 0) { - visibility.append("!").append(numBlockListed); - } - visibility.append("]"); - - return visibility.toString(); - } - - @VisibleForTesting - /* package */ static String verboseScanResultSummary(AccessPoint accessPoint, ScanResult result, - String bssid, long nowMs) { - StringBuilder stringBuilder = new StringBuilder(); - stringBuilder.append(" \n{").append(result.BSSID); - if (result.BSSID.equals(bssid)) { - stringBuilder.append("*"); - } - stringBuilder.append("=").append(result.frequency); - stringBuilder.append(",").append(result.level); - int speed = getSpecificApSpeed(result, accessPoint.getScoredNetworkCache()); - if (speed != AccessPoint.Speed.NONE) { - stringBuilder.append(",") - .append(accessPoint.getSpeedLabel(speed)); - } - int ageSeconds = (int) (nowMs - result.timestamp / 1000) / 1000; - stringBuilder.append(",").append(ageSeconds).append("s"); - stringBuilder.append("}"); - return stringBuilder.toString(); - } - - @AccessPoint.Speed - private static int getSpecificApSpeed(ScanResult result, - Map<String, TimestampedScoredNetwork> scoredNetworkCache) { - TimestampedScoredNetwork timedScore = scoredNetworkCache.get(result.BSSID); - if (timedScore == null) { - return AccessPoint.Speed.NONE; - } - // For debugging purposes we may want to use mRssi rather than result.level as the average - // speed wil be determined by mRssi - return timedScore.getScore().calculateBadge(result.level); - } - - public static String getMeteredLabel(Context context, WifiConfiguration config) { - // meteredOverride is whether the user manually set the metered setting or not. - // meteredHint is whether the network itself is telling us that it is metered - if (config.meteredOverride == WifiConfiguration.METERED_OVERRIDE_METERED - || (config.meteredHint && !isMeteredOverridden(config))) { - return context.getString(R.string.wifi_metered_label); - } - return context.getString(R.string.wifi_unmetered_label); - } - - /** - * Returns the Internet icon resource for a given RSSI level. - * - * @param level The number of bars to show (0-4) - * @param noInternet True if a connected Wi-Fi network cannot access the Internet - */ - public static int getInternetIconResource(int level, boolean noInternet) { - int wifiLevel = level; - if (wifiLevel < 0) { - Log.e(TAG, "Wi-Fi level is out of range! level:" + level); - wifiLevel = 0; - } else if (level >= WIFI_PIE.length) { - Log.e(TAG, "Wi-Fi level is out of range! level:" + level); - wifiLevel = WIFI_PIE.length - 1; - } - return noInternet ? NO_INTERNET_WIFI_PIE[wifiLevel] : WIFI_PIE[wifiLevel]; - } - - /** - * Returns the Hotspot network icon resource. - * - * @param deviceType The device type of Hotspot network - */ - public static int getHotspotIconResource(int deviceType) { - return switch (deviceType) { - case NetworkProviderInfo.DEVICE_TYPE_PHONE -> R.drawable.ic_hotspot_phone; - case NetworkProviderInfo.DEVICE_TYPE_TABLET -> R.drawable.ic_hotspot_tablet; - case NetworkProviderInfo.DEVICE_TYPE_LAPTOP -> R.drawable.ic_hotspot_laptop; - case NetworkProviderInfo.DEVICE_TYPE_WATCH -> R.drawable.ic_hotspot_watch; - case NetworkProviderInfo.DEVICE_TYPE_AUTO -> R.drawable.ic_hotspot_auto; - default -> R.drawable.ic_hotspot_phone; // Return phone icon as default. - }; - } - - /** - * Wrapper the {@link #getInternetIconResource} for testing compatibility. - */ - public static class InternetIconInjector { - - protected final Context mContext; - - public InternetIconInjector(Context context) { - mContext = context; - } - - /** - * Returns the Internet icon for a given RSSI level. - * - * @param noInternet True if a connected Wi-Fi network cannot access the Internet - * @param level The number of bars to show (0-4) - */ - public Drawable getIcon(boolean noInternet, int level) { - return mContext.getDrawable(WifiUtils.getInternetIconResource(level, noInternet)); - } - } - - public static boolean isMeteredOverridden(WifiConfiguration config) { - return config.meteredOverride != WifiConfiguration.METERED_OVERRIDE_NONE; - } - - /** - * Returns the Intent for Wi-Fi dialog. - * - * @param key The Wi-Fi entry key - * @param connectForCaller True if a chosen WifiEntry request to connect to - */ - public static Intent getWifiDialogIntent(String key, boolean connectForCaller) { - final Intent intent = new Intent(ACTION_WIFI_DIALOG); - intent.putExtra(EXTRA_CHOSEN_WIFI_ENTRY_KEY, key); - intent.putExtra(EXTRA_CONNECT_FOR_CALLER, connectForCaller); - return intent; - } - - /** - * Returns the Intent for Wi-Fi network details settings. - * - * @param key The Wi-Fi entry key - */ - public static Intent getWifiDetailsSettingsIntent(String key) { - final Intent intent = new Intent(ACTION_WIFI_DETAILS_SETTINGS); - final Bundle bundle = new Bundle(); - bundle.putString(KEY_CHOSEN_WIFIENTRY_KEY, key); - intent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, bundle); - return intent; - } - - /** - * Returns the string of Wi-Fi tethering summary for connected devices. - * - * @param context The application context - * @param connectedDevices The count of connected devices - */ - public static String getWifiTetherSummaryForConnectedDevices(Context context, - int connectedDevices) { - MessageFormat msgFormat = new MessageFormat( - context.getResources().getString(R.string.wifi_tether_connected_summary), - Locale.getDefault()); - Map<String, Object> arguments = new HashMap<>(); - arguments.put("count", connectedDevices); - return msgFormat.format(arguments); - } -} diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.kt b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.kt new file mode 100644 index 000000000000..7d614f0e4d39 --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.kt @@ -0,0 +1,462 @@ +/* + * Copyright (C) 2024 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.settingslib.wifi + +import android.content.Context +import android.content.Intent +import android.graphics.drawable.Drawable +import android.icu.text.MessageFormat +import android.net.wifi.ScanResult +import android.net.wifi.WifiConfiguration +import android.net.wifi.WifiConfiguration.NetworkSelectionStatus +import android.net.wifi.sharedconnectivity.app.NetworkProviderInfo +import android.os.Bundle +import android.os.SystemClock +import android.util.Log +import androidx.annotation.VisibleForTesting +import com.android.settingslib.R +import com.android.settingslib.flags.Flags.newStatusBarIcons +import java.util.Locale + + +open class WifiUtils { + /** + * Wrapper the [.getInternetIconResource] for testing compatibility. + */ + class InternetIconInjector(protected val context: Context) { + /** + * Returns the Internet icon for a given RSSI level. + * + * @param noInternet True if a connected Wi-Fi network cannot access the Internet + * @param level The number of bars to show (0-4) + */ + fun getIcon(noInternet: Boolean, level: Int): Drawable? { + return context.getDrawable(getInternetIconResource(level, noInternet)) + } + } + + companion object { + private const val TAG = "WifiUtils" + private const val INVALID_RSSI = -127 + + /** + * The intent action shows Wi-Fi dialog to connect Wi-Fi network. + * + * + * Input: The calling package should put the chosen + * com.android.wifitrackerlib.WifiEntry#getKey() to a string extra in the request bundle into + * the [.EXTRA_CHOSEN_WIFI_ENTRY_KEY]. + * + * + * Output: Nothing. + */ + @JvmField + @VisibleForTesting + val ACTION_WIFI_DIALOG = "com.android.settings.WIFI_DIALOG" + + /** + * Specify a key that indicates the WifiEntry to be configured. + */ + @JvmField + @VisibleForTesting + val EXTRA_CHOSEN_WIFI_ENTRY_KEY = "key_chosen_wifientry_key" + + /** + * The lookup key for a boolean that indicates whether a chosen WifiEntry request to connect to. + * `true` means a chosen WifiEntry request to connect to. + */ + @JvmField + @VisibleForTesting + val EXTRA_CONNECT_FOR_CALLER = "connect_for_caller" + + /** + * The intent action shows network details settings to allow configuration of Wi-Fi. + * + * + * In some cases, a matching Activity may not exist, so ensure you + * safeguard against this. + * + * + * Input: The calling package should put the chosen + * com.android.wifitrackerlib.WifiEntry#getKey() to a string extra in the request bundle into + * the [.KEY_CHOSEN_WIFIENTRY_KEY]. + * + * + * Output: Nothing. + */ + const val ACTION_WIFI_DETAILS_SETTINGS = "android.settings.WIFI_DETAILS_SETTINGS" + const val KEY_CHOSEN_WIFIENTRY_KEY = "key_chosen_wifientry_key" + const val EXTRA_SHOW_FRAGMENT_ARGUMENTS = ":settings:show_fragment_args" + + @JvmField + val WIFI_PIE = getIconsBasedOnFlag() + + private fun getIconsBasedOnFlag(): IntArray { + return if (newStatusBarIcons()) { + intArrayOf( + R.drawable.ic_wifi_0, + R.drawable.ic_wifi_1, + R.drawable.ic_wifi_2, + R.drawable.ic_wifi_3, + R.drawable.ic_wifi_4 + ) + } else { + intArrayOf( + com.android.internal.R.drawable.ic_wifi_signal_0, + com.android.internal.R.drawable.ic_wifi_signal_1, + com.android.internal.R.drawable.ic_wifi_signal_2, + com.android.internal.R.drawable.ic_wifi_signal_3, + com.android.internal.R.drawable.ic_wifi_signal_4 + ) + } + } + + val NO_INTERNET_WIFI_PIE = getErrorIconsBasedOnFlag() + + private fun getErrorIconsBasedOnFlag(): IntArray { + return if (newStatusBarIcons()) { + intArrayOf( + R.drawable.ic_wifi_0_error, + R.drawable.ic_wifi_1_error, + R.drawable.ic_wifi_2_error, + R.drawable.ic_wifi_3_error, + R.drawable.ic_wifi_4_error + ) + } else { + intArrayOf( + R.drawable.ic_no_internet_wifi_signal_0, + R.drawable.ic_no_internet_wifi_signal_1, + R.drawable.ic_no_internet_wifi_signal_2, + R.drawable.ic_no_internet_wifi_signal_3, + R.drawable.ic_no_internet_wifi_signal_4 + ) + } + } + + + @JvmStatic + fun buildLoggingSummary(accessPoint: AccessPoint, config: WifiConfiguration?): String { + val summary = StringBuilder() + val info = accessPoint.info + // Add RSSI/band information for this config, what was seen up to 6 seconds ago + // verbose WiFi Logging is only turned on thru developers settings + if (accessPoint.isActive && info != null) { + summary.append(" f=" + info.frequency.toString()) + } + summary.append(" " + getVisibilityStatus(accessPoint)) + if (config != null && (config.networkSelectionStatus.networkSelectionStatus + != NetworkSelectionStatus.NETWORK_SELECTION_ENABLED) + ) { + summary.append(" (" + config.networkSelectionStatus.networkStatusString) + if (config.networkSelectionStatus.disableTime > 0) { + val now = System.currentTimeMillis() + val diff = (now - config.networkSelectionStatus.disableTime) / 1000 + val sec = diff % 60 // seconds + val min = diff / 60 % 60 // minutes + val hour = min / 60 % 60 // hours + summary.append(", ") + if (hour > 0) summary.append(hour.toString() + "h ") + summary.append(min.toString() + "m ") + summary.append(sec.toString() + "s ") + } + summary.append(")") + } + if (config != null) { + val networkStatus = config.networkSelectionStatus + for (reason in 0..NetworkSelectionStatus.getMaxNetworkSelectionDisableReason()) { + if (networkStatus.getDisableReasonCounter(reason) != 0) { + summary.append(" ") + .append( + NetworkSelectionStatus + .getNetworkSelectionDisableReasonString(reason) + ) + .append("=") + .append(networkStatus.getDisableReasonCounter(reason)) + } + } + } + return summary.toString() + } + + /** + * Returns the visibility status of the WifiConfiguration. + * + * @return autojoin debugging information + * TODO: use a string formatter + * ["rssi 5Ghz", "num results on 5GHz" / "rssi 5Ghz", "num results on 5GHz"] + * For instance [-40,5/-30,2] + */ + @JvmStatic + @VisibleForTesting + fun getVisibilityStatus(accessPoint: AccessPoint): String { + val info = accessPoint.info + val visibility = StringBuilder() + val scans24GHz = StringBuilder() + val scans5GHz = StringBuilder() + val scans60GHz = StringBuilder() + var bssid: String? = null + if (accessPoint.isActive && info != null) { + bssid = info.bssid + if (bssid != null) { + visibility.append(" ").append(bssid) + } + visibility.append(" standard = ").append(info.wifiStandard) + visibility.append(" rssi=").append(info.rssi) + visibility.append(" ") + visibility.append(" score=").append(info.getScore()) + if (accessPoint.speed != AccessPoint.Speed.NONE) { + visibility.append(" speed=").append(accessPoint.speedLabel) + } + visibility.append(String.format(" tx=%.1f,", info.successfulTxPacketsPerSecond)) + visibility.append(String.format("%.1f,", info.retriedTxPacketsPerSecond)) + visibility.append(String.format("%.1f ", info.lostTxPacketsPerSecond)) + visibility.append(String.format("rx=%.1f", info.successfulRxPacketsPerSecond)) + } + var maxRssi5 = INVALID_RSSI + var maxRssi24 = INVALID_RSSI + var maxRssi60 = INVALID_RSSI + val maxDisplayedScans = 4 + var num5 = 0 // number of scanned BSSID on 5GHz band + var num24 = 0 // number of scanned BSSID on 2.4Ghz band + var num60 = 0 // number of scanned BSSID on 60Ghz band + val numBlockListed = 0 + + // TODO: sort list by RSSI or age + val nowMs = SystemClock.elapsedRealtime() + for (result in accessPoint.getScanResults()) { + if (result == null) { + continue + } + if (result.frequency >= AccessPoint.LOWER_FREQ_5GHZ && + result.frequency <= AccessPoint.HIGHER_FREQ_5GHZ + ) { + // Strictly speaking: [4915, 5825] + num5++ + if (result.level > maxRssi5) { + maxRssi5 = result.level + } + if (num5 <= maxDisplayedScans) { + scans5GHz.append( + verboseScanResultSummary( + accessPoint, result, bssid, + nowMs + ) + ) + } + } else if (result.frequency >= AccessPoint.LOWER_FREQ_24GHZ && + result.frequency <= AccessPoint.HIGHER_FREQ_24GHZ + ) { + // Strictly speaking: [2412, 2482] + num24++ + if (result.level > maxRssi24) { + maxRssi24 = result.level + } + if (num24 <= maxDisplayedScans) { + scans24GHz.append( + verboseScanResultSummary( + accessPoint, result, bssid, + nowMs + ) + ) + } + } else if (result.frequency >= AccessPoint.LOWER_FREQ_60GHZ && + result.frequency <= AccessPoint.HIGHER_FREQ_60GHZ + ) { + // Strictly speaking: [60000, 61000] + num60++ + if (result.level > maxRssi60) { + maxRssi60 = result.level + } + if (num60 <= maxDisplayedScans) { + scans60GHz.append( + verboseScanResultSummary( + accessPoint, result, bssid, + nowMs + ) + ) + } + } + } + visibility.append(" [") + if (num24 > 0) { + visibility.append("(").append(num24).append(")") + if (num24 > maxDisplayedScans) { + visibility.append("max=").append(maxRssi24).append(",") + } + visibility.append(scans24GHz.toString()) + } + visibility.append(";") + if (num5 > 0) { + visibility.append("(").append(num5).append(")") + if (num5 > maxDisplayedScans) { + visibility.append("max=").append(maxRssi5).append(",") + } + visibility.append(scans5GHz.toString()) + } + visibility.append(";") + if (num60 > 0) { + visibility.append("(").append(num60).append(")") + if (num60 > maxDisplayedScans) { + visibility.append("max=").append(maxRssi60).append(",") + } + visibility.append(scans60GHz.toString()) + } + if (numBlockListed > 0) { + visibility.append("!").append(numBlockListed) + } + visibility.append("]") + return visibility.toString() + } + + @JvmStatic + @VisibleForTesting /* package */ fun verboseScanResultSummary( + accessPoint: AccessPoint, + result: ScanResult, + bssid: String?, + nowMs: Long + ): String { + val stringBuilder = StringBuilder() + stringBuilder.append(" \n{").append(result.BSSID) + if (result.BSSID == bssid) { + stringBuilder.append("*") + } + stringBuilder.append("=").append(result.frequency) + stringBuilder.append(",").append(result.level) + val speed = getSpecificApSpeed(result, accessPoint.scoredNetworkCache) + if (speed != AccessPoint.Speed.NONE) { + stringBuilder.append(",") + .append(accessPoint.getSpeedLabel(speed)) + } + val ageSeconds = (nowMs - result.timestamp / 1000).toInt() / 1000 + stringBuilder.append(",").append(ageSeconds).append("s") + stringBuilder.append("}") + return stringBuilder.toString() + } + + @AccessPoint.Speed + private fun getSpecificApSpeed( + result: ScanResult, + scoredNetworkCache: Map<String, TimestampedScoredNetwork> + ): Int { + val timedScore = scoredNetworkCache[result.BSSID] ?: return AccessPoint.Speed.NONE + // For debugging purposes we may want to use mRssi rather than result.level as the average + // speed wil be determined by mRssi + return timedScore.score.calculateBadge(result.level) + } + + @JvmStatic + fun getMeteredLabel(context: Context, config: WifiConfiguration): String { + // meteredOverride is whether the user manually set the metered setting or not. + // meteredHint is whether the network itself is telling us that it is metered + return if (config.meteredOverride == WifiConfiguration.METERED_OVERRIDE_METERED || + config.meteredHint && !isMeteredOverridden( + config + ) + ) { + context.getString(R.string.wifi_metered_label) + } else context.getString(R.string.wifi_unmetered_label) + } + + /** + * Returns the Internet icon resource for a given RSSI level. + * + * @param level The number of bars to show (0-4) + * @param noInternet True if a connected Wi-Fi network cannot access the Internet + */ + @JvmStatic + fun getInternetIconResource(level: Int, noInternet: Boolean): Int { + var wifiLevel = level + if (wifiLevel < 0) { + Log.e(TAG, "Wi-Fi level is out of range! level:$level") + wifiLevel = 0 + } else if (level >= WIFI_PIE.size) { + Log.e(TAG, "Wi-Fi level is out of range! level:$level") + wifiLevel = WIFI_PIE.size - 1 + } + return if (noInternet) NO_INTERNET_WIFI_PIE[wifiLevel] else WIFI_PIE[wifiLevel] + } + + /** + * Returns the Hotspot network icon resource. + * + * @param deviceType The device type of Hotspot network + */ + @JvmStatic + fun getHotspotIconResource(deviceType: Int): Int { + return when (deviceType) { + NetworkProviderInfo.DEVICE_TYPE_PHONE -> R.drawable.ic_hotspot_phone + NetworkProviderInfo.DEVICE_TYPE_TABLET -> R.drawable.ic_hotspot_tablet + NetworkProviderInfo.DEVICE_TYPE_LAPTOP -> R.drawable.ic_hotspot_laptop + NetworkProviderInfo.DEVICE_TYPE_WATCH -> R.drawable.ic_hotspot_watch + NetworkProviderInfo.DEVICE_TYPE_AUTO -> R.drawable.ic_hotspot_auto + else -> R.drawable.ic_hotspot_phone + } + } + + @JvmStatic + fun isMeteredOverridden(config: WifiConfiguration): Boolean { + return config.meteredOverride != WifiConfiguration.METERED_OVERRIDE_NONE + } + + /** + * Returns the Intent for Wi-Fi dialog. + * + * @param key The Wi-Fi entry key + * @param connectForCaller True if a chosen WifiEntry request to connect to + */ + @JvmStatic + fun getWifiDialogIntent(key: String?, connectForCaller: Boolean): Intent { + val intent = Intent(ACTION_WIFI_DIALOG) + intent.putExtra(EXTRA_CHOSEN_WIFI_ENTRY_KEY, key) + intent.putExtra(EXTRA_CONNECT_FOR_CALLER, connectForCaller) + return intent + } + + /** + * Returns the Intent for Wi-Fi network details settings. + * + * @param key The Wi-Fi entry key + */ + @JvmStatic + fun getWifiDetailsSettingsIntent(key: String?): Intent { + val intent = Intent(ACTION_WIFI_DETAILS_SETTINGS) + val bundle = Bundle() + bundle.putString(KEY_CHOSEN_WIFIENTRY_KEY, key) + intent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, bundle) + return intent + } + + /** + * Returns the string of Wi-Fi tethering summary for connected devices. + * + * @param context The application context + * @param connectedDevices The count of connected devices + */ + @JvmStatic + fun getWifiTetherSummaryForConnectedDevices( + context: Context, + connectedDevices: Int + ): String { + val msgFormat = MessageFormat( + context.resources.getString(R.string.wifi_tether_connected_summary), + Locale.getDefault() + ) + val arguments: MutableMap<String, Any> = HashMap() + arguments["count"] = connectedDevices + return msgFormat.format(arguments) + } + } +} |