1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settingslib.wifi; 18 19 import android.content.Context; 20 import android.net.wifi.ScanResult; 21 import android.net.wifi.WifiConfiguration; 22 import android.net.wifi.WifiInfo; 23 import android.os.SystemClock; 24 import android.support.annotation.VisibleForTesting; 25 26 import com.android.settingslib.R; 27 28 import java.util.Map; 29 30 public class WifiUtils { 31 buildLoggingSummary(AccessPoint accessPoint, WifiConfiguration config)32 public static String buildLoggingSummary(AccessPoint accessPoint, WifiConfiguration config) { 33 final StringBuilder summary = new StringBuilder(); 34 final WifiInfo info = accessPoint.getInfo(); 35 // Add RSSI/band information for this config, what was seen up to 6 seconds ago 36 // verbose WiFi Logging is only turned on thru developers settings 37 if (accessPoint.isActive() && info != null) { 38 summary.append(" f=" + Integer.toString(info.getFrequency())); 39 } 40 summary.append(" " + getVisibilityStatus(accessPoint)); 41 if (config != null && !config.getNetworkSelectionStatus().isNetworkEnabled()) { 42 summary.append(" (" + config.getNetworkSelectionStatus().getNetworkStatusString()); 43 if (config.getNetworkSelectionStatus().getDisableTime() > 0) { 44 long now = System.currentTimeMillis(); 45 long diff = (now - config.getNetworkSelectionStatus().getDisableTime()) / 1000; 46 long sec = diff % 60; //seconds 47 long min = (diff / 60) % 60; //minutes 48 long hour = (min / 60) % 60; //hours 49 summary.append(", "); 50 if (hour > 0) summary.append(Long.toString(hour) + "h "); 51 summary.append(Long.toString(min) + "m "); 52 summary.append(Long.toString(sec) + "s "); 53 } 54 summary.append(")"); 55 } 56 57 if (config != null) { 58 WifiConfiguration.NetworkSelectionStatus networkStatus = 59 config.getNetworkSelectionStatus(); 60 for (int index = WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_ENABLE; 61 index < WifiConfiguration.NetworkSelectionStatus 62 .NETWORK_SELECTION_DISABLED_MAX; index++) { 63 if (networkStatus.getDisableReasonCounter(index) != 0) { 64 summary.append(" " + WifiConfiguration.NetworkSelectionStatus 65 .getNetworkDisableReasonString(index) + "=" 66 + networkStatus.getDisableReasonCounter(index)); 67 } 68 } 69 } 70 71 return summary.toString(); 72 } 73 74 /** 75 * Returns the visibility status of the WifiConfiguration. 76 * 77 * @return autojoin debugging information 78 * TODO: use a string formatter 79 * ["rssi 5Ghz", "num results on 5GHz" / "rssi 5Ghz", "num results on 5GHz"] 80 * For instance [-40,5/-30,2] 81 */ 82 @VisibleForTesting getVisibilityStatus(AccessPoint accessPoint)83 static String getVisibilityStatus(AccessPoint accessPoint) { 84 final WifiInfo info = accessPoint.getInfo(); 85 StringBuilder visibility = new StringBuilder(); 86 StringBuilder scans24GHz = new StringBuilder(); 87 StringBuilder scans5GHz = new StringBuilder(); 88 String bssid = null; 89 90 if (accessPoint.isActive() && info != null) { 91 bssid = info.getBSSID(); 92 if (bssid != null) { 93 visibility.append(" ").append(bssid); 94 } 95 visibility.append(" rssi=").append(info.getRssi()); 96 visibility.append(" "); 97 visibility.append(" score=").append(info.score); 98 if (accessPoint.getSpeed() != AccessPoint.Speed.NONE) { 99 visibility.append(" speed=").append(accessPoint.getSpeedLabel()); 100 } 101 visibility.append(String.format(" tx=%.1f,", info.txSuccessRate)); 102 visibility.append(String.format("%.1f,", info.txRetriesRate)); 103 visibility.append(String.format("%.1f ", info.txBadRate)); 104 visibility.append(String.format("rx=%.1f", info.rxSuccessRate)); 105 } 106 107 int maxRssi5 = WifiConfiguration.INVALID_RSSI; 108 int maxRssi24 = WifiConfiguration.INVALID_RSSI; 109 final int maxDisplayedScans = 4; 110 int num5 = 0; // number of scanned BSSID on 5GHz band 111 int num24 = 0; // number of scanned BSSID on 2.4Ghz band 112 int numBlackListed = 0; 113 114 // TODO: sort list by RSSI or age 115 long nowMs = SystemClock.elapsedRealtime(); 116 for (ScanResult result : accessPoint.getScanResults()) { 117 if (result == null) { 118 continue; 119 } 120 if (result.frequency >= AccessPoint.LOWER_FREQ_5GHZ 121 && result.frequency <= AccessPoint.HIGHER_FREQ_5GHZ) { 122 // Strictly speaking: [4915, 5825] 123 num5++; 124 125 if (result.level > maxRssi5) { 126 maxRssi5 = result.level; 127 } 128 if (num5 <= maxDisplayedScans) { 129 scans5GHz.append( 130 verboseScanResultSummary(accessPoint, result, bssid, 131 nowMs)); 132 } 133 } else if (result.frequency >= AccessPoint.LOWER_FREQ_24GHZ 134 && result.frequency <= AccessPoint.HIGHER_FREQ_24GHZ) { 135 // Strictly speaking: [2412, 2482] 136 num24++; 137 138 if (result.level > maxRssi24) { 139 maxRssi24 = result.level; 140 } 141 if (num24 <= maxDisplayedScans) { 142 scans24GHz.append( 143 verboseScanResultSummary(accessPoint, result, bssid, 144 nowMs)); 145 } 146 } 147 } 148 visibility.append(" ["); 149 if (num24 > 0) { 150 visibility.append("(").append(num24).append(")"); 151 if (num24 > maxDisplayedScans) { 152 visibility.append("max=").append(maxRssi24).append(","); 153 } 154 visibility.append(scans24GHz.toString()); 155 } 156 visibility.append(";"); 157 if (num5 > 0) { 158 visibility.append("(").append(num5).append(")"); 159 if (num5 > maxDisplayedScans) { 160 visibility.append("max=").append(maxRssi5).append(","); 161 } 162 visibility.append(scans5GHz.toString()); 163 } 164 if (numBlackListed > 0) { 165 visibility.append("!").append(numBlackListed); 166 } 167 visibility.append("]"); 168 169 return visibility.toString(); 170 } 171 172 @VisibleForTesting verboseScanResultSummary(AccessPoint accessPoint, ScanResult result, String bssid, long nowMs)173 /* package */ static String verboseScanResultSummary(AccessPoint accessPoint, ScanResult result, 174 String bssid, long nowMs) { 175 StringBuilder stringBuilder = new StringBuilder(); 176 stringBuilder.append(" \n{").append(result.BSSID); 177 if (result.BSSID.equals(bssid)) { 178 stringBuilder.append("*"); 179 } 180 stringBuilder.append("=").append(result.frequency); 181 stringBuilder.append(",").append(result.level); 182 int speed = getSpecificApSpeed(result, accessPoint.getScoredNetworkCache()); 183 if (speed != AccessPoint.Speed.NONE) { 184 stringBuilder.append(",") 185 .append(accessPoint.getSpeedLabel(speed)); 186 } 187 int ageSeconds = (int) (nowMs - result.timestamp / 1000) / 1000; 188 stringBuilder.append(",").append(ageSeconds).append("s"); 189 stringBuilder.append("}"); 190 return stringBuilder.toString(); 191 } 192 193 @AccessPoint.Speed getSpecificApSpeed(ScanResult result, Map<String, TimestampedScoredNetwork> scoredNetworkCache)194 private static int getSpecificApSpeed(ScanResult result, 195 Map<String, TimestampedScoredNetwork> scoredNetworkCache) { 196 TimestampedScoredNetwork timedScore = scoredNetworkCache.get(result.BSSID); 197 if (timedScore == null) { 198 return AccessPoint.Speed.NONE; 199 } 200 // For debugging purposes we may want to use mRssi rather than result.level as the average 201 // speed wil be determined by mRssi 202 return timedScore.getScore().calculateBadge(result.level); 203 } 204 getMeteredLabel(Context context, WifiConfiguration config)205 public static String getMeteredLabel(Context context, WifiConfiguration config) { 206 // meteredOverride is whether the user manually set the metered setting or not. 207 // meteredHint is whether the network itself is telling us that it is metered 208 if (config.meteredOverride == WifiConfiguration.METERED_OVERRIDE_METERED 209 || (config.meteredHint && !isMeteredOverridden(config))) { 210 return context.getString(R.string.wifi_metered_label); 211 } 212 return context.getString(R.string.wifi_unmetered_label); 213 } 214 isMeteredOverridden(WifiConfiguration config)215 public static boolean isMeteredOverridden(WifiConfiguration config) { 216 return config.meteredOverride != WifiConfiguration.METERED_OVERRIDE_NONE; 217 } 218 } 219