1 /* 2 * Copyright (C) 2021 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.tv.settings.library.network; 18 19 import android.annotation.IntDef; 20 import android.annotation.MainThread; 21 import android.annotation.TargetApi; 22 import android.net.wifi.ScanResult; 23 import android.net.wifi.WifiConfiguration; 24 import android.net.wifi.WifiInfo; 25 import android.net.wifi.WifiManager; 26 import android.os.Build; 27 import android.text.TextUtils; 28 29 import androidx.annotation.NonNull; 30 31 import com.android.wifitrackerlib.PasspointWifiEntry; 32 import com.android.wifitrackerlib.WifiEntry; 33 34 import java.lang.annotation.Retention; 35 import java.lang.annotation.RetentionPolicy; 36 import java.util.ArrayList; 37 import java.util.List; 38 39 @TargetApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) 40 public class AccessPoint implements Comparable<AccessPoint> { 41 public static final int SECURITY_NONE = WifiInfo.SECURITY_TYPE_OPEN; 42 public static final int SECURITY_WEP = WifiInfo.SECURITY_TYPE_WEP; 43 public static final int SECURITY_PSK = WifiInfo.SECURITY_TYPE_PSK; 44 public static final int SECURITY_EAP = WifiInfo.SECURITY_TYPE_EAP; 45 public static final int SECURITY_OWE = WifiInfo.SECURITY_TYPE_OWE; 46 public static final int SECURITY_SAE = WifiInfo.SECURITY_TYPE_SAE; 47 public static final int SECURITY_EAP_SUITE_B = 48 WifiInfo.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT; 49 50 public static final String KEY_PREFIX_AP = "AP:"; 51 52 @IntDef({Speed.NONE, Speed.SLOW, Speed.MODERATE, Speed.FAST, Speed.VERY_FAST}) 53 @Retention(RetentionPolicy.SOURCE) 54 public @interface Speed { 55 /** 56 * Constant value representing an unlabeled / unscored network. 57 */ 58 int NONE = 0; 59 /** 60 * Constant value representing a slow speed network connection. 61 */ 62 int SLOW = 5; 63 /** 64 * Constant value representing a medium speed network connection. 65 */ 66 int MODERATE = 10; 67 /** 68 * Constant value representing a fast speed network connection. 69 */ 70 int FAST = 20; 71 /** 72 * Constant value representing a very fast speed network connection. 73 */ 74 int VERY_FAST = 30; 75 } 76 77 private final WifiEntry mWifiEntry; 78 79 private final WifiEntry.WifiEntryCallback mEntryCallback = new WifiEntry.WifiEntryCallback() { 80 @Override 81 public void onUpdated() { 82 if (mAccessPointListener != null) { 83 mAccessPointListener.onAccessPointChanged(AccessPoint.this); 84 mAccessPointListener.onLevelChanged(AccessPoint.this); 85 } 86 } 87 }; 88 89 AccessPoint.AccessPointListener mAccessPointListener; 90 AccessPoint(WifiEntry wifiEntry)91 public AccessPoint(WifiEntry wifiEntry) { 92 mWifiEntry = wifiEntry; 93 } 94 95 /* 96 * Use this for any new code that was not written using legacy WifiTracker AccessPoint 97 * interface. 98 */ getWifiEntry()99 public WifiEntry getWifiEntry() { 100 return mWifiEntry; 101 } 102 103 @Override compareTo(@onNull AccessPoint other)104 public int compareTo(@NonNull AccessPoint other) { 105 return WifiEntry.WIFI_PICKER_COMPARATOR.compare(mWifiEntry, other.mWifiEntry); 106 } 107 108 @Override equals(Object other)109 public boolean equals(Object other) { 110 if (!(other instanceof AccessPoint)) return false; 111 return (this.compareTo((AccessPoint) other) == 0); 112 } 113 114 @Override hashCode()115 public int hashCode() { 116 return mWifiEntry.hashCode(); 117 } 118 119 @Override toString()120 public String toString() { 121 return mWifiEntry.toString(); 122 } 123 124 /** 125 * Generates an AccessPoint key for a given scan result 126 * 127 * @param result Scan result 128 * @return AccessPoint key 129 */ getKey(ScanResult result)130 public static String getKey(ScanResult result) { 131 return getKey(result.SSID, result.BSSID, getSecurity(result)); 132 } 133 134 /** 135 * Returns the AccessPoint key for a normal non-Passpoint network by ssid/bssid and security. 136 */ getKey(String ssid, String bssid, int security)137 private static String getKey(String ssid, String bssid, int security) { 138 StringBuilder builder = new StringBuilder(); 139 builder.append(KEY_PREFIX_AP); 140 if (TextUtils.isEmpty(ssid)) { 141 builder.append(bssid); 142 } else { 143 builder.append(ssid); 144 } 145 builder.append(',').append(security); 146 return builder.toString(); 147 } 148 getKey()149 public String getKey() { 150 return getKey(getSsidStr(), mWifiEntry.getMacAddress(), getSecurity()); 151 } 152 getConfig()153 public WifiConfiguration getConfig() { 154 return mWifiEntry.getWifiConfiguration(); 155 } 156 getInfo()157 public WifiInfo getInfo() { 158 return null; 159 } 160 161 /** 162 * Returns the number of levels to show for a Wifi icon, from 0 to 163 * {@link WifiManager#getMaxSignalLevel()}. 164 */ getLevel()165 public int getLevel() { 166 return mWifiEntry.getLevel(); 167 } 168 169 /** 170 * Returns if the network should be considered metered. 171 */ isMetered()172 public boolean isMetered() { 173 return mWifiEntry.isMetered(); 174 } 175 getSecurity(WifiEntry wifiEntry)176 public static int getSecurity(WifiEntry wifiEntry) { 177 return getSingleSecurityTypeFromMultipleSecurityTypes(wifiEntry.getSecurityTypes()); 178 } 179 180 /** 181 * Returns a single WifiInfo security type from the list of multiple WifiInfo security 182 * types supported by an entry. 183 * 184 * Single security types will have a 1-to-1 mapping. 185 * Multiple security type networks will collapse to the lowest security type in the group: 186 * - Open/OWE -> Open 187 * - PSK/SAE -> PSK 188 * - EAP/EAP-WPA3 -> EAP 189 * This mapping is copied from {@link WifiEntry} to avoid unintentional changes to TVSettings 190 * behavior when connecting to a given network. 191 */ getSingleSecurityTypeFromMultipleSecurityTypes( @onNull List<Integer> securityTypes)192 private static int getSingleSecurityTypeFromMultipleSecurityTypes( 193 @NonNull List<Integer> securityTypes) { 194 if (securityTypes.isEmpty()) { 195 return WifiInfo.SECURITY_TYPE_UNKNOWN; 196 } 197 198 if (securityTypes.size() == 2) { 199 if (securityTypes.contains(WifiInfo.SECURITY_TYPE_OPEN)) { 200 return WifiInfo.SECURITY_TYPE_OPEN; 201 } 202 if (securityTypes.contains(WifiInfo.SECURITY_TYPE_PSK)) { 203 return WifiInfo.SECURITY_TYPE_PSK; 204 } 205 if (securityTypes.contains(WifiInfo.SECURITY_TYPE_EAP)) { 206 return WifiInfo.SECURITY_TYPE_EAP; 207 } 208 } 209 210 // Default to the first security type if we don't need any special mapping. 211 return securityTypes.get(0); 212 } 213 getSecurity()214 public int getSecurity() { 215 return getSecurity(mWifiEntry); 216 } 217 getSsidStr()218 public String getSsidStr() { 219 return mWifiEntry.getSsid(); 220 } 221 getSsid()222 public CharSequence getSsid() { 223 return getSsidStr(); 224 } 225 226 /** 227 * Returns the display title for the AccessPoint, such as for an AccessPointPreference's title. 228 */ getTitle()229 public String getTitle() { 230 return mWifiEntry.getTitle(); 231 } 232 getSettingsSummary()233 public String getSettingsSummary() { 234 return ""; 235 } 236 isActive()237 public boolean isActive() { 238 return mWifiEntry.getConnectedState() == WifiEntry.CONNECTED_STATE_CONNECTED; 239 } 240 241 /** 242 * Return true if this AccessPoint represents a Passpoint AP. 243 */ isPasspoint()244 public boolean isPasspoint() { 245 return mWifiEntry instanceof PasspointWifiEntry; 246 } 247 isSaved()248 public boolean isSaved() { 249 return mWifiEntry.isSaved(); 250 } 251 setListener(AccessPoint.AccessPointListener listener)252 public void setListener(AccessPoint.AccessPointListener listener) { 253 mAccessPointListener = listener; 254 mWifiEntry.setListener(listener != null ? mEntryCallback : null); 255 } 256 convertToQuotedString(String string)257 public static String convertToQuotedString(String string) { 258 return "\"" + string + "\""; 259 } 260 getSecurity(ScanResult result)261 private static int getSecurity(ScanResult result) { 262 List<Integer> securityTypes = new ArrayList<>(); 263 for (int securityType : result.getSecurityTypes()) { 264 securityTypes.add(securityType); 265 } 266 return getSingleSecurityTypeFromMultipleSecurityTypes(securityTypes); 267 } 268 269 /** 270 * Callbacks relaying changes to the AccessPoint representation. 271 * 272 * <p>All methods are invoked on the Main Thread. 273 */ 274 public interface AccessPointListener { 275 276 /** 277 * Indicates a change to the externally visible state of the AccessPoint trigger by an 278 * update of ScanResults, saved configuration state, connection state, or score 279 * (labels/metered) state. 280 * 281 * <p>Clients should refresh their view of the AccessPoint to match the updated state when 282 * this is invoked. Overall this method is extraneous if clients are listening to 283 * {@link WifiTracker.WifiListener#onAccessPointsChanged()} callbacks. 284 * 285 * <p>Examples of changes include signal strength, connection state, speed label, and 286 * generally anything that would impact the summary string. 287 * 288 * @param accessPoint The accessPoint object the listener was registered on which has 289 * changed 290 */ 291 @MainThread onAccessPointChanged(AccessPoint accessPoint)292 void onAccessPointChanged(AccessPoint accessPoint); 293 294 /** 295 * Indicates the "wifi pie signal level" has changed, retrieved via calls to 296 * {@link AccessPoint#getLevel()}. 297 * 298 * <p>This call is a subset of {@link #onAccessPointChanged(AccessPoint)} , hence is also 299 * extraneous if the client is already reacting to that or the 300 * {@link WifiTracker.WifiListener#onAccessPointsChanged()} callbacks. 301 * 302 * @param accessPoint The accessPoint object the listener was registered on whose level has 303 * changed 304 */ 305 @MainThread onLevelChanged(AccessPoint accessPoint)306 void onLevelChanged(AccessPoint accessPoint); 307 } 308 } 309