我正在以编程方式连接 DashCam相机的WIFI 网络,该网络无法访问互联网。连接成功,但几秒钟后它自动断开连接。我正在开发一个强烈推荐此功能的DashCam移动应用。
通过ConnectorUtils连接扫描结果
WifiConfiguration config = ConfigSecurities.getWifiConfiguration(wifiManager, scanResult);
if (config != null) {
ConnectorUtils.connectToConfiguredNetwork(wifiManager, config, true);
} else
ConnectorUtils.connectToWifi(getApplicationContext(), wifiManager, scanResult, "12345678");
ConnectorUtils类
public class ConnectorUtils {
private static final int MAX_PRIORITY = 99999;
private static final String TAG = ConnectorUtils.class.getSimpleName();
@Nullable
private static ConnectivityManager.NetworkCallback networkCallback;
public static boolean isAlreadyConnected(@Nullable WifiManager wifiManager, @Nullable String bssid) {
if (bssid != null && wifiManager != null) {
if (wifiManager.getConnectionInfo() != null && wifiManager.getConnectionInfo().getBSSID() != null &&
wifiManager.getConnectionInfo().getIpAddress() != 0 &&
Objects.equals(bssid, wifiManager.getConnectionInfo().getBSSID())) {
return true;
}
}
return false;
}
@SuppressWarnings("UnusedReturnValue")
private static boolean checkForExcessOpenNetworkAndSave(@NonNull final ContentResolver resolver, @NonNull final WifiManager wifiMgr) {
final List<WifiConfiguration> configurations = wifiMgr.getConfiguredNetworks();
sortByPriority(configurations);
boolean modified = false;
int tempCount = 0;
final int numOpenNetworksKept = Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1
? Settings.Secure.getInt(resolver, Settings.Global.WIFI_NUM_OPEN_NETWORKS_KEPT, 10)
: Settings.Secure.getInt(resolver, Settings.Secure.WIFI_NUM_OPEN_NETWORKS_KEPT, 10);
for (int i = configurations.size() - 1; i >= 0; i--) {
final WifiConfiguration config = configurations.get(i);
if (Objects.equals(ConfigSecurities.SECURITY_NONE, ConfigSecurities.getSecurity(config))) {
tempCount++;
if (tempCount >= numOpenNetworksKept) {
modified = true;
wifiMgr.removeNetwork(config.networkId);
}
}
}
return !modified || wifiMgr.saveConfiguration();
}
private static int getMaxPriority(@Nullable final WifiManager wifiManager) {
if (wifiManager == null) {
return 0;
}
final List<WifiConfiguration> configurations = wifiManager.getConfiguredNetworks();
int pri = 0;
for (final WifiConfiguration config : configurations) {
if (config.priority > pri) {
pri = config.priority;
}
}
return pri;
}
private static int shiftPriorityAndSave(@Nullable final WifiManager wifiMgr) {
if (wifiMgr == null) {
return 0;
}
final List<WifiConfiguration> configurations = wifiMgr.getConfiguredNetworks();
sortByPriority(configurations);
final int size = configurations.size();
for (int i = 0; i < size; i++) {
final WifiConfiguration config = configurations.get(i);
config.priority = i;
wifiMgr.updateNetwork(config);
}
wifiMgr.saveConfiguration();
return size;
}
@Nullable
private static String trimQuotes(@Nullable String str) {
if (str != null && !str.isEmpty()) {
return str.replaceAll("^\"*", "").replaceAll("\"*$", "");
}
return str;
}
@SuppressWarnings("unused")
public static int getPowerPercentage(int power) {
int i;
if (power <= -93) {
i = 0;
} else if (-25 <= power && power <= 0) {
i = 100;
} else {
i = 125 + power;
}
return i;
}
static boolean isHexWepKey(@Nullable String wepKey) {
final int passwordLen = wepKey == null ? 0 : wepKey.length();
return (passwordLen == 10 || passwordLen == 26 || passwordLen == 58) && wepKey.matches("[0-9A-Fa-f]*");
}
private static void sortByPriority(@NonNull final List<WifiConfiguration> configurations) {
Collections.sort(configurations, (o1, o2) -> o1.priority - o2.priority);
}
@SuppressWarnings("unused")
public static int frequencyToChannel(int freq) {
if (2412 <= freq && freq <= 2484) {
return (freq - 2412) / 5 + 1;
} else if (5170 <= freq && freq <= 5825) {
return (freq - 5170) / 5 + 34;
} else {
return -1;
}
}
@RequiresPermission(allOf = {ACCESS_FINE_LOCATION, ACCESS_WIFI_STATE})
public static boolean connectToWifi(@NonNull final Context context, @Nullable final WifiManager wifiManager, @NonNull final ScanResult scanResult, @NonNull final String password) {
if (wifiManager == null) {
return false;
}
if (isAndroidQOrLater()) {
final ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
return connectAndroidQ(connectivityManager, scanResult, password);
}
return connectPreAndroidQ(context, wifiManager, scanResult, password);
}
@RequiresPermission(allOf = {ACCESS_FINE_LOCATION, ACCESS_WIFI_STATE})
private static boolean connectPreAndroidQ(@NonNull final Context context, @Nullable final WifiManager wifiManager, @NonNull final ScanResult scanResult, @NonNull final String password) {
if (wifiManager == null) {
return false;
}
WifiConfiguration config = ConfigSecurities.getWifiConfiguration(wifiManager, scanResult);
if (config != null && password.isEmpty()) {
// wifiLog("PASSWORD WAS EMPTY. TRYING TO CONNECT TO EXISTING NETWORK CONFIGURATION");
return connectToConfiguredNetwork(wifiManager, config, true);
}
if (!cleanPreviousConfiguration(wifiManager, config)) {
// wifiLog("COULDN'T REMOVE PREVIOUS CONFIG, CONNECTING TO EXISTING ONE");
return connectToConfiguredNetwork(wifiManager, config, true);
}
final String security = ConfigSecurities.getSecurity(scanResult);
if (Objects.equals(ConfigSecurities.SECURITY_NONE, security)) {
checkForExcessOpenNetworkAndSave(context.getContentResolver(), wifiManager);
}
config = new WifiConfiguration();
config.SSID = convertToQuotedString(scanResult.SSID);
config.BSSID = scanResult.BSSID;
ConfigSecurities.setupSecurity(config, security, password);
int id = wifiManager.addNetwork(config);
// wifiLog("Network ID: " + id);
if (id == -1) {
return false;
}
if (!wifiManager.saveConfiguration()) {
// wifiLog("Couldn't save wifi config");
return false;
}
// We have to retrieve the WifiConfiguration after save
config = ConfigSecurities.getWifiConfiguration(wifiManager, config);
if (config == null) {
// wifiLog("Error getting wifi config after save. (config == null)");
return false;
}
return connectToConfiguredNetwork(wifiManager, config, true);
}
@RequiresPermission(allOf = {ACCESS_FINE_LOCATION, ACCESS_WIFI_STATE})
public static boolean connectToConfiguredNetwork(@Nullable WifiManager wifiManager, @Nullable WifiConfiguration config, boolean reassociate) {
if (config == null || wifiManager == null) {
return false;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
return disableAllButOne(wifiManager, config) && (reassociate ? wifiManager.reassociate() : wifiManager.reconnect());
}
// Make it the highest priority.
int newPri = getMaxPriority(wifiManager) + 1;
if (newPri > MAX_PRIORITY) {
newPri = shiftPriorityAndSave(wifiManager);
config = ConfigSecurities.getWifiConfiguration(wifiManager, config);
if (config == null) {
return false;
}
}
// Set highest priority to this configured network
config.priority = newPri;
int networkId = wifiManager.updateNetwork(config);
if (networkId == -1) {
return false;
}
// Do not disable others
if (!wifiManager.enableNetwork(networkId, false)) {
return false;
}
if (!wifiManager.saveConfiguration()) {
return false;
}
// We have to retrieve the WifiConfiguration after save.
config = ConfigSecurities.getWifiConfiguration(wifiManager, config);
return config != null && disableAllButOne(wifiManager, config) && (reassociate ? wifiManager.reassociate() : wifiManager.reconnect());
}
@RequiresApi(Build.VERSION_CODES.Q)
private static boolean connectAndroidQ(@Nullable ConnectivityManager connectivityManager, @NonNull ScanResult scanResult, @NonNull String password) {
if (connectivityManager == null) {
return false;
}
WifiNetworkSpecifier.Builder wifiNetworkSpecifierBuilder = new WifiNetworkSpecifier.Builder()
.setSsid(scanResult.SSID)
.setBssid(MacAddress.fromString(scanResult.BSSID));
final String security = ConfigSecurities.getSecurity(scanResult);
ConfigSecurities.setupWifiNetworkSpecifierSecurities(wifiNetworkSpecifierBuilder, security, password);
NetworkRequest networkRequest = new NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.setNetworkSpecifier(wifiNetworkSpecifierBuilder.build())
.build();
connectivityManager.requestNetwork(networkRequest, networkCallback);
return true;
}
private static boolean disableAllButOne(@Nullable final WifiManager wifiManager, @Nullable final WifiConfiguration config) {
if (wifiManager == null) {
return false;
}
@Nullable final List<WifiConfiguration> configurations = wifiManager.getConfiguredNetworks();
if (configurations == null || config == null || configurations.isEmpty()) {
return false;
}
boolean result = false;
for (WifiConfiguration wifiConfig : configurations) {
if (wifiConfig == null) {
continue;
}
if (wifiConfig.networkId == config.networkId) {
result = wifiManager.enableNetwork(wifiConfig.networkId, true);
} else {
wifiManager.disableNetwork(wifiConfig.networkId);
}
}
// wifiLog("disableAllButOne " + result);
return result;
}
@SuppressWarnings("UnusedReturnValue")
private static boolean disableAllButOne(@Nullable final WifiManager wifiManager, @Nullable final ScanResult scanResult) {
if (wifiManager == null) {
return false;
}
@Nullable final List<WifiConfiguration> configurations = wifiManager.getConfiguredNetworks();
if (configurations == null || scanResult == null || configurations.isEmpty()) {
return false;
}
boolean result = false;
for (WifiConfiguration wifiConfig : configurations) {
if (wifiConfig == null) {
continue;
}
if (Objects.equals(scanResult.BSSID, wifiConfig.BSSID) && Objects.equals(scanResult.SSID, trimQuotes(wifiConfig.SSID))) {
result = wifiManager.enableNetwork(wifiConfig.networkId, true);
} else {
wifiManager.disableNetwork(wifiConfig.networkId);
}
}
return result;
}
@SuppressLint("MissingPermission")
public static boolean enableConfiguredNetworkIfPossible(@Nullable final WifiManager wifiManager, @Nullable final ScanResult scanResult) {
if (wifiManager == null) {
Log.d(TAG, "enableConfiguredNetworkIfPossible: WifiManager null");
return false;
}
@Nullable final List<WifiConfiguration> configurations = wifiManager.getConfiguredNetworks();
if (configurations == null || scanResult == null || configurations.isEmpty()) {
Log.d(TAG, "enableConfiguredNetworkIfPossible: configurations null");
return false;
}
boolean result = false;
for (WifiConfiguration wifiConfig : configurations)
if (Objects.equals(scanResult.SSID, trimQuotes(wifiConfig.SSID))) {
// wifiConfig.priority = 40;
// int netId = wifiManager.updateNetwork(wifiConfig);
Log.d(TAG, "enableConfiguredNetworkIfPossible: " + wifiConfig.SSID);
connectToConfiguredNetwork(wifiManager, wifiConfig,false);
// result = wifiManager.enableNetwork(wifiConfig.networkId, true);
// wifiManager.reconnect();
break;
} else {
Log.d(TAG, "ScanResult.BSSID:: " + scanResult.BSSID);
Log.d(TAG, "WifiConfig.BSSID:: " + wifiConfig.BSSID);
Log.d(TAG, "ScanResult.SSID:: " + scanResult.SSID);
Log.d(TAG, "WifiConfig.SSID:: " + wifiConfig.SSID);
}
// wifiLog("enableConfiguredNetworkIfPossible " + result);
return result;
}
@RequiresPermission(allOf = {ACCESS_FINE_LOCATION, ACCESS_WIFI_STATE})
static boolean cleanPreviousConfiguration(@Nullable final WifiManager wifiManager, @NonNull final ScanResult scanResult) {
if (wifiManager == null) {
return false;
}
//On Android 6.0 (API level 23) and above if my app did not create the configuration in the first place, it can not remove it either.
final WifiConfiguration config = ConfigSecurities.getWifiConfiguration(wifiManager, scanResult);
// wifiLog("Attempting to remove previous network config...");
if (config == null) {
return true;
}
if (wifiManager.removeNetwork(config.networkId)) {
wifiManager.saveConfiguration();
return true;
}
return false;
}
static boolean cleanPreviousConfiguration(@Nullable final WifiManager wifiManager, @Nullable final WifiConfiguration config) {
//On Android 6.0 (API level 23) and above if my app did not create the configuration in the first place, it can not remove it either.
if (wifiManager == null) {
return false;
}
// wifiLog("Attempting to remove previous network config...");
if (config == null) {
return true;
}
if (wifiManager.removeNetwork(config.networkId)) {
wifiManager.saveConfiguration();
return true;
}
return false;
}
static void reenableAllHotspots(@Nullable WifiManager wifi) {
if (wifi == null) {
return;
}
final List<WifiConfiguration> configurations = wifi.getConfiguredNetworks();
if (configurations != null && !configurations.isEmpty()) {
for (final WifiConfiguration config : configurations) {
wifi.enableNetwork(config.networkId, false);
}
}
}
private static boolean isAndroidQOrLater() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q;
}
public static String convertToQuotedString(String string) {
if (TextUtils.isEmpty(string))
return "";
final int lastPos = string.length() - 1;
if (lastPos < 0 || (string.charAt(0) == '"' && string.charAt(lastPos) == '"')) {
return string;
}
return "\"" + string + "\"";
}
public boolean isWifiEnable(WifiManager wifiManager) {
return (wifiManager.isWifiEnabled() && wifiManager.getConnectionInfo().getNetworkId() != -1);
}
public static int getConfiguredNetworkId(WifiManager wifiManager, String ssid) {
List<WifiConfiguration> list = wifiManager.getConfiguredNetworks();
for (WifiConfiguration config : list) {
if (config.SSID != null && config.SSID.equals("\"" + ssid + "\"")) {
return config.networkId;
}
}
return -1;
}
}
ConfigSecurities类
public class ConfigSecurities {
static final String SECURITY_NONE = "OPEN";
static final String SECURITY_WEP = "WEP";
static final String SECURITY_PSK = "PSK";
static final String SECURITY_EAP = "EAP";
/**
* Fill in the security fields of WifiConfiguration config.
*
* @param config The object to fill.
* @param security If is OPEN, password is ignored.
* @param password Password of the network if security is not OPEN.
*/
@RequiresPermission(allOf = {ACCESS_FINE_LOCATION, ACCESS_WIFI_STATE})
static void setupSecurity(@NonNull WifiConfiguration config, String security, @NonNull final String password) {
config.allowedAuthAlgorithms.clear();
config.allowedGroupCiphers.clear();
config.allowedKeyManagement.clear();
config.allowedPairwiseCiphers.clear();
config.allowedProtocols.clear();
// wifiLog("Setting up security " + security);
switch (security) {
case SECURITY_NONE:
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
config.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
config.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40);
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP104);
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
break;
case SECURITY_WEP:
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
config.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
config.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED);
config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40);
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP104);
// WEP-40, WEP-104, and 256-bit WEP (WEP-232?)
if (ConnectorUtils.isHexWepKey(password)) {
config.wepKeys[0] = password;
} else {
config.wepKeys[0] = ConnectorUtils.convertToQuotedString(password);
}
break;
case SECURITY_PSK:
config.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
config.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40);
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP104);
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
if (password.matches("[0-9A-Fa-f]{64}")) {
config.preSharedKey = password;
} else {
config.preSharedKey = ConnectorUtils.convertToQuotedString(password);
}
break;
case SECURITY_EAP:
config.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
config.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40);
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP104);
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X);
config.preSharedKey = ConnectorUtils.convertToQuotedString(password);
break;
default:
// wifiLog("Invalid security type: " + security);
break;
}
}
@TargetApi(Build.VERSION_CODES.Q)
static void setupWifiNetworkSpecifierSecurities(@NonNull WifiNetworkSpecifier.Builder wifiNetworkSpecifierBuilder, String security, @NonNull final String password) {
// wifiLog("Setting up WifiNetworkSpecifier.Builder " + security);
switch (security) {
case SECURITY_NONE:
// nothing to do
break;
case SECURITY_WEP:
// no longer possible
break;
case SECURITY_PSK:
case SECURITY_EAP:
wifiNetworkSpecifierBuilder.setWpa2Passphrase(password);
break;
default:
// wifiLog("Invalid security type: " + security);
break;
}
}
@RequiresPermission(allOf = {ACCESS_FINE_LOCATION, ACCESS_WIFI_STATE})
@Nullable
static WifiConfiguration getWifiConfiguration(@NonNull final WifiManager wifiMgr, @NonNull final WifiConfiguration configToFind) {
final String ssid = configToFind.SSID;
if (ssid == null || ssid.isEmpty()) {
return null;
}
final String bssid = configToFind.BSSID != null ? configToFind.BSSID : "";
final String security = getSecurity(configToFind);
final List<WifiConfiguration> configurations = wifiMgr.getConfiguredNetworks();
if (configurations == null) {
// wifiLog("NULL configs");
return null;
}
for (final WifiConfiguration config : configurations) {
if (bssid.equals(config.BSSID) || ssid.equals(config.SSID)) {
final String configSecurity = getSecurity(config);
if (Objects.equals(security, configSecurity)) {
return config;
}
}
}
// wifiLog("Couldn't find " + ssid);
return null;
}
@RequiresPermission(allOf = {ACCESS_FINE_LOCATION, ACCESS_WIFI_STATE})
@Nullable
static WifiConfiguration getWifiConfiguration(@NonNull final WifiManager wifiManager, @NonNull final String ssid) {
final List<WifiConfiguration> configuredNetworks = wifiManager.getConfiguredNetworks();
final String findSSID = ('"' + ssid + '"');
for (final WifiConfiguration wifiConfiguration : configuredNetworks) {
if (wifiConfiguration.SSID.equals(findSSID)) {
return wifiConfiguration;
}
}
return null;
}
@RequiresPermission(allOf = {ACCESS_FINE_LOCATION, ACCESS_WIFI_STATE})
@Nullable
public static WifiConfiguration getWifiConfiguration(@NonNull final WifiManager wifiManager, @NonNull final ScanResult scanResult) {
if (scanResult.BSSID == null || scanResult.SSID == null || scanResult.SSID.isEmpty() || scanResult.BSSID.isEmpty()) {
return null;
}
final String ssid = ConnectorUtils.convertToQuotedString(scanResult.SSID);
final String bssid = scanResult.BSSID;
final String security = getSecurity(scanResult);
final List<WifiConfiguration> configurations = wifiManager.getConfiguredNetworks();
if (configurations == null) {
return null;
}
for (final WifiConfiguration config : configurations) {
if (bssid.equals(config.BSSID) || ssid.equals(config.SSID)) {
final String configSecurity = getSecurity(config);
if (Objects.equals(security, configSecurity)) {
return config;
}
}
}
return null;
}
static String getSecurity(@NonNull WifiConfiguration config) {
String security = SECURITY_NONE;
final Collection<String> securities = new ArrayList<>();
if (config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.NONE)) {
// If we never set group ciphers, wpa_supplicant puts all of them.
// For open, we don't set group ciphers.
// For WEP, we specifically only set WEP40 and WEP104, so CCMP
// and TKIP should not be there.
if (config.wepKeys[0] != null) {
security = SECURITY_WEP;
} else {
security = SECURITY_NONE;
}
securities.add(security);
}
if (config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_EAP) ||
config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.IEEE8021X)) {
security = SECURITY_EAP;
securities.add(security);
}
if (config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK)) {
security = SECURITY_PSK;
securities.add(security);
}
// wifiLog("Got Security Via WifiConfiguration " + securities);
return security;
}
}