| /* |
| * 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.settings.wifi; |
| |
| import android.app.admin.DevicePolicyManager; |
| import android.content.ComponentName; |
| import android.content.ContentResolver; |
| import android.content.Context; |
| import android.content.pm.PackageManager; |
| import android.net.NetworkCapabilities; |
| import android.net.wifi.ScanResult; |
| import android.net.wifi.WifiConfiguration; |
| import android.provider.Settings; |
| import android.text.TextUtils; |
| |
| import com.android.settingslib.wifi.AccessPoint; |
| |
| import java.nio.charset.StandardCharsets; |
| |
| public class WifiUtils { |
| |
| private static final int SSID_ASCII_MIN_LENGTH = 1; |
| private static final int SSID_ASCII_MAX_LENGTH = 32; |
| private static final int PASSWORD_MIN_LENGTH = 8; |
| private static final int PASSWORD_MAX_LENGTH = 63; |
| |
| |
| public static boolean isSSIDTooLong(String ssid) { |
| if (TextUtils.isEmpty(ssid)) { |
| return false; |
| } |
| return ssid.getBytes(StandardCharsets.UTF_8).length > SSID_ASCII_MAX_LENGTH; |
| } |
| |
| public static boolean isSSIDTooShort(String ssid) { |
| if (TextUtils.isEmpty(ssid)) { |
| return true; |
| } |
| return ssid.length() < SSID_ASCII_MIN_LENGTH; |
| } |
| |
| public static boolean isHotspotPasswordValid(String password) { |
| if (TextUtils.isEmpty(password)) { |
| return false; |
| } |
| |
| final int length = password.length(); |
| return length >= PASSWORD_MIN_LENGTH && length <= PASSWORD_MAX_LENGTH; |
| } |
| |
| /** |
| * This method is a stripped and negated version of WifiConfigStore.canModifyNetwork. |
| * |
| * @param context Context of caller |
| * @param config The WiFi config. |
| * @return true if Settings cannot modify the config due to lockDown. |
| */ |
| public static boolean isNetworkLockedDown(Context context, WifiConfiguration config) { |
| if (config == null) { |
| return false; |
| } |
| |
| final DevicePolicyManager dpm = |
| (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE); |
| final PackageManager pm = context.getPackageManager(); |
| |
| // Check if device has DPM capability. If it has and dpm is still null, then we |
| // treat this case with suspicion and bail out. |
| if (pm.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN) && dpm == null) { |
| return true; |
| } |
| |
| boolean isConfigEligibleForLockdown = false; |
| if (dpm != null) { |
| final ComponentName deviceOwner = dpm.getDeviceOwnerComponentOnAnyUser(); |
| if (deviceOwner != null) { |
| final int deviceOwnerUserId = dpm.getDeviceOwnerUserId(); |
| try { |
| final int deviceOwnerUid = pm.getPackageUidAsUser(deviceOwner.getPackageName(), |
| deviceOwnerUserId); |
| isConfigEligibleForLockdown = deviceOwnerUid == config.creatorUid; |
| } catch (PackageManager.NameNotFoundException e) { |
| // don't care |
| } |
| } |
| } |
| if (!isConfigEligibleForLockdown) { |
| return false; |
| } |
| |
| final ContentResolver resolver = context.getContentResolver(); |
| final boolean isLockdownFeatureEnabled = Settings.Global.getInt(resolver, |
| Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN, 0) != 0; |
| return isLockdownFeatureEnabled; |
| } |
| |
| /** Returns true if the provided NetworkCapabilities indicate a captive portal network. */ |
| public static boolean canSignIntoNetwork(NetworkCapabilities capabilities) { |
| return (capabilities != null |
| && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL)); |
| } |
| |
| /** |
| * Provides a simple way to generate a new {@link WifiConfiguration} obj from |
| * {@link ScanResult} or {@link AccessPoint}. Either {@code accessPoint} or {@code scanResult |
| * } input should be not null for retrieving information, otherwise will throw |
| * IllegalArgumentException. |
| * This method prefers to take {@link AccessPoint} input in priority. Therefore this method |
| * will take {@link AccessPoint} input as preferred data extraction source when you input |
| * both {@link AccessPoint} and {@link ScanResult}, and ignore {@link ScanResult} input. |
| * |
| * Duplicated and simplified method from {@link WifiConfigController#getConfig()}. |
| * TODO(b/120827021): Should be removed if the there is have a common one in shared place (e.g. |
| * SettingsLib). |
| * |
| * @param accessPoint Input data for retrieving WifiConfiguration. |
| * @param scanResult Input data for retrieving WifiConfiguration. |
| * @return WifiConfiguration obj based on input. |
| */ |
| public static WifiConfiguration getWifiConfig(AccessPoint accessPoint, ScanResult scanResult, |
| String password) { |
| if (accessPoint == null && scanResult == null) { |
| throw new IllegalArgumentException( |
| "At least one of AccessPoint and ScanResult input is required."); |
| } |
| |
| final WifiConfiguration config = new WifiConfiguration(); |
| final int security; |
| |
| if (accessPoint == null) { |
| config.SSID = AccessPoint.convertToQuotedString(scanResult.SSID); |
| security = getAccessPointSecurity(scanResult); |
| } else { |
| if (!accessPoint.isSaved()) { |
| config.SSID = AccessPoint.convertToQuotedString( |
| accessPoint.getSsidStr()); |
| } else { |
| config.networkId = accessPoint.getConfig().networkId; |
| config.hiddenSSID = accessPoint.getConfig().hiddenSSID; |
| } |
| security = accessPoint.getSecurity(); |
| } |
| |
| switch (security) { |
| case AccessPoint.SECURITY_NONE: |
| config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); |
| break; |
| |
| case AccessPoint.SECURITY_WEP: |
| config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); |
| config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN); |
| config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED); |
| if (!TextUtils.isEmpty(password)) { |
| int length = password.length(); |
| // WEP-40, WEP-104, and 256-bit WEP (WEP-232?) |
| if ((length == 10 || length == 26 || length == 58) |
| && password.matches("[0-9A-Fa-f]*")) { |
| config.wepKeys[0] = password; |
| } else { |
| config.wepKeys[0] = '"' + password + '"'; |
| } |
| } |
| break; |
| |
| case AccessPoint.SECURITY_PSK: |
| config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK); |
| if (!TextUtils.isEmpty(password)) { |
| if (password.matches("[0-9A-Fa-f]{64}")) { |
| config.preSharedKey = password; |
| } else { |
| config.preSharedKey = '"' + password + '"'; |
| } |
| } |
| break; |
| |
| case AccessPoint.SECURITY_EAP: |
| case AccessPoint.SECURITY_EAP_SUITE_B: |
| config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP); |
| config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X); |
| if (security == AccessPoint.SECURITY_EAP_SUITE_B) { |
| config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SUITE_B_192); |
| config.requirePMF = true; |
| config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.GCMP_256); |
| config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256); |
| config.allowedGroupManagementCiphers.set(WifiConfiguration.GroupMgmtCipher |
| .BIP_GMAC_256); |
| // allowedSuiteBCiphers will be set according to certificate type |
| } |
| |
| if (!TextUtils.isEmpty(password)) { |
| config.enterpriseConfig.setPassword(password); |
| } |
| break; |
| case AccessPoint.SECURITY_SAE: |
| config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SAE); |
| config.requirePMF = true; |
| if (!TextUtils.isEmpty(password)) { |
| config.preSharedKey = '"' + password + '"'; |
| } |
| break; |
| |
| case AccessPoint.SECURITY_OWE: |
| config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.OWE); |
| config.requirePMF = true; |
| break; |
| |
| default: |
| break; |
| } |
| |
| return config; |
| } |
| |
| |
| /** |
| * Gets security value from ScanResult. |
| * |
| * Duplicated method from {@link AccessPoint#getSecurity(ScanResult)}. |
| * TODO(b/120827021): Should be removed if the there is have a common one in shared place (e.g. |
| * SettingsLib). |
| * |
| * @param result ScanResult |
| * @return Related security value based on {@link AccessPoint}. |
| */ |
| public static int getAccessPointSecurity(ScanResult result) { |
| if (result.capabilities.contains("WEP")) { |
| return AccessPoint.SECURITY_WEP; |
| } else if (result.capabilities.contains("SAE")) { |
| return AccessPoint.SECURITY_SAE; |
| } else if (result.capabilities.contains("PSK")) { |
| return AccessPoint.SECURITY_PSK; |
| } else if (result.capabilities.contains("EAP_SUITE_B_192")) { |
| return AccessPoint.SECURITY_EAP_SUITE_B; |
| } else if (result.capabilities.contains("EAP")) { |
| return AccessPoint.SECURITY_EAP; |
| } else if (result.capabilities.contains("OWE")) { |
| return AccessPoint.SECURITY_OWE; |
| } |
| |
| return AccessPoint.SECURITY_NONE; |
| } |
| |
| |
| public static final int CONNECT_TYPE_OTHERS = 0; |
| public static final int CONNECT_TYPE_OPEN_NETWORK = 1; |
| public static final int CONNECT_TYPE_SAVED_NETWORK = 2; |
| public static final int CONNECT_TYPE_OSU_PROVISION = 3; |
| |
| /** |
| * Gets the connecting type of {@link AccessPoint}. |
| */ |
| public static int getConnectingType(AccessPoint accessPoint) { |
| final WifiConfiguration config = accessPoint.getConfig(); |
| if (accessPoint.isOsuProvider()) { |
| return CONNECT_TYPE_OSU_PROVISION; |
| } else if ((accessPoint.getSecurity() == AccessPoint.SECURITY_NONE) || |
| (accessPoint.getSecurity() == AccessPoint.SECURITY_OWE) || |
| (accessPoint.getSecurity() == AccessPoint.SECURITY_OWE_TRANSITION)) { |
| return CONNECT_TYPE_OPEN_NETWORK; |
| } else if (accessPoint.isSaved() && config != null |
| && config.getNetworkSelectionStatus() != null |
| && config.getNetworkSelectionStatus().getHasEverConnected()) { |
| return CONNECT_TYPE_SAVED_NETWORK; |
| } else if (accessPoint.isPasspoint()) { |
| // Access point provided by an installed Passpoint provider, connect using |
| // the associated config. |
| return CONNECT_TYPE_SAVED_NETWORK; |
| } else { |
| return CONNECT_TYPE_OTHERS; |
| } |
| } |
| } |