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.settings.wifi; 18 19 import android.app.admin.DevicePolicyManager; 20 import android.content.ComponentName; 21 import android.content.ContentResolver; 22 import android.content.Context; 23 import android.content.pm.PackageManager; 24 import android.net.NetworkCapabilities; 25 import android.net.wifi.ScanResult; 26 import android.net.wifi.SoftApConfiguration; 27 import android.net.wifi.WifiConfiguration; 28 import android.os.UserHandle; 29 import android.os.UserManager; 30 import android.provider.Settings; 31 import android.text.TextUtils; 32 33 import com.android.settings.Utils; 34 import com.android.wifitrackerlib.WifiEntry; 35 36 import java.nio.charset.StandardCharsets; 37 38 /** A utility class for Wi-Fi functions. */ 39 public class WifiUtils extends com.android.settingslib.wifi.WifiUtils { 40 41 private static final int SSID_ASCII_MIN_LENGTH = 1; 42 private static final int SSID_ASCII_MAX_LENGTH = 32; 43 44 isSSIDTooLong(String ssid)45 public static boolean isSSIDTooLong(String ssid) { 46 if (TextUtils.isEmpty(ssid)) { 47 return false; 48 } 49 return ssid.getBytes(StandardCharsets.UTF_8).length > SSID_ASCII_MAX_LENGTH; 50 } 51 isSSIDTooShort(String ssid)52 public static boolean isSSIDTooShort(String ssid) { 53 if (TextUtils.isEmpty(ssid)) { 54 return true; 55 } 56 return ssid.length() < SSID_ASCII_MIN_LENGTH; 57 } 58 59 /** 60 * Check if the hotspot password is valid. 61 */ isHotspotPasswordValid(String password, int securityType)62 public static boolean isHotspotPasswordValid(String password, int securityType) { 63 final SoftApConfiguration.Builder configBuilder = new SoftApConfiguration.Builder(); 64 try { 65 configBuilder.setPassphrase(password, securityType); 66 } catch (IllegalArgumentException e) { 67 return false; 68 } 69 return true; 70 } 71 72 /** 73 * This method is a stripped and negated version of WifiConfigStore.canModifyNetwork. 74 * 75 * @param context Context of caller 76 * @param config The WiFi config. 77 * @return true if Settings cannot modify the config due to lockDown. 78 */ isNetworkLockedDown(Context context, WifiConfiguration config)79 public static boolean isNetworkLockedDown(Context context, WifiConfiguration config) { 80 if (config == null) { 81 return false; 82 } 83 84 final DevicePolicyManager dpm = 85 (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE); 86 final PackageManager pm = context.getPackageManager(); 87 final UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE); 88 89 // Check if device has DPM capability. If it has and dpm is still null, then we 90 // treat this case with suspicion and bail out. 91 if (pm.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN) && dpm == null) { 92 return true; 93 } 94 95 boolean isConfigEligibleForLockdown = false; 96 if (dpm != null) { 97 final ComponentName deviceOwner = dpm.getDeviceOwnerComponentOnAnyUser(); 98 if (deviceOwner != null) { 99 final int deviceOwnerUserId = dpm.getDeviceOwnerUserId(); 100 try { 101 final int deviceOwnerUid = pm.getPackageUidAsUser(deviceOwner.getPackageName(), 102 deviceOwnerUserId); 103 isConfigEligibleForLockdown = deviceOwnerUid == config.creatorUid; 104 } catch (PackageManager.NameNotFoundException e) { 105 // don't care 106 } 107 } else if (dpm.isOrganizationOwnedDeviceWithManagedProfile()) { 108 int profileOwnerUserId = Utils.getManagedProfileId(um, UserHandle.myUserId()); 109 final ComponentName profileOwner = dpm.getProfileOwnerAsUser(profileOwnerUserId); 110 if (profileOwner != null) { 111 try { 112 final int profileOwnerUid = pm.getPackageUidAsUser( 113 profileOwner.getPackageName(), profileOwnerUserId); 114 isConfigEligibleForLockdown = profileOwnerUid == config.creatorUid; 115 } catch (PackageManager.NameNotFoundException e) { 116 // don't care 117 } 118 } 119 } 120 } 121 if (!isConfigEligibleForLockdown) { 122 return false; 123 } 124 125 final ContentResolver resolver = context.getContentResolver(); 126 final boolean isLockdownFeatureEnabled = Settings.Global.getInt(resolver, 127 Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN, 0) != 0; 128 return isLockdownFeatureEnabled; 129 } 130 131 /** Returns true if the provided NetworkCapabilities indicate a captive portal network. */ canSignIntoNetwork(NetworkCapabilities capabilities)132 public static boolean canSignIntoNetwork(NetworkCapabilities capabilities) { 133 return (capabilities != null 134 && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL)); 135 } 136 137 /** 138 * Provides a simple way to generate a new {@link WifiConfiguration} obj from 139 * {@link ScanResult} or {@link WifiEntry}. Either {@code wifiEntry} or {@code scanResult 140 * } input should be not null for retrieving information, otherwise will throw 141 * IllegalArgumentException. 142 * This method prefers to take {@link WifiEntry} input in priority. Therefore this method 143 * will take {@link WifiEntry} input as preferred data extraction source when you input 144 * both {@link WifiEntry} and {@link ScanResult}, and ignore {@link ScanResult} input. 145 * 146 * Duplicated and simplified method from {@link WifiConfigController#getConfig()}. 147 * TODO(b/120827021): Should be removed if the there is have a common one in shared place (e.g. 148 * SettingsLib). 149 * 150 * @param wifiEntry Input data for retrieving WifiConfiguration. 151 * @param scanResult Input data for retrieving WifiConfiguration. 152 * @return WifiConfiguration obj based on input. 153 */ getWifiConfig(WifiEntry wifiEntry, ScanResult scanResult)154 public static WifiConfiguration getWifiConfig(WifiEntry wifiEntry, ScanResult scanResult) { 155 if (wifiEntry == null && scanResult == null) { 156 throw new IllegalArgumentException( 157 "At least one of WifiEntry and ScanResult input is required."); 158 } 159 160 final WifiConfiguration config = new WifiConfiguration(); 161 final int security; 162 163 if (wifiEntry == null) { 164 config.SSID = "\"" + scanResult.SSID + "\""; 165 security = getWifiEntrySecurity(scanResult); 166 } else { 167 if (wifiEntry.getWifiConfiguration() == null) { 168 config.SSID = "\"" + wifiEntry.getSsid() + "\""; 169 } else { 170 config.networkId = wifiEntry.getWifiConfiguration().networkId; 171 config.hiddenSSID = wifiEntry.getWifiConfiguration().hiddenSSID; 172 } 173 security = wifiEntry.getSecurity(); 174 } 175 176 switch (security) { 177 case WifiEntry.SECURITY_NONE: 178 config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_OPEN); 179 break; 180 181 case WifiEntry.SECURITY_WEP: 182 config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_WEP); 183 break; 184 185 case WifiEntry.SECURITY_PSK: 186 config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_PSK); 187 break; 188 189 case WifiEntry.SECURITY_EAP_SUITE_B: 190 config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP_SUITE_B); 191 break; 192 193 case WifiEntry.SECURITY_EAP: 194 config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_EAP); 195 break; 196 197 case WifiEntry.SECURITY_SAE: 198 config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_SAE); 199 break; 200 201 case WifiEntry.SECURITY_OWE: 202 config.setSecurityParams(WifiConfiguration.SECURITY_TYPE_OWE); 203 break; 204 205 default: 206 break; 207 } 208 return config; 209 } 210 211 /** 212 * Gets security value from ScanResult. 213 * 214 * @param result ScanResult 215 * @return Related security value based on {@link WifiEntry}. 216 */ getWifiEntrySecurity(ScanResult result)217 public static int getWifiEntrySecurity(ScanResult result) { 218 if (result.capabilities.contains("WEP")) { 219 return WifiEntry.SECURITY_WEP; 220 } else if (result.capabilities.contains("SAE")) { 221 return WifiEntry.SECURITY_SAE; 222 } else if (result.capabilities.contains("PSK")) { 223 return WifiEntry.SECURITY_PSK; 224 } else if (result.capabilities.contains("EAP_SUITE_B_192")) { 225 return WifiEntry.SECURITY_EAP_SUITE_B; 226 } else if (result.capabilities.contains("EAP")) { 227 return WifiEntry.SECURITY_EAP; 228 } else if (result.capabilities.contains("OWE")) { 229 return WifiEntry.SECURITY_OWE; 230 } 231 232 return WifiEntry.SECURITY_NONE; 233 } 234 } 235