I'm currently implementing two apps: a client app which communicates with another server app via TLS Socket connection. The server phone (Android 7.1) needs to create a hotspot with passphrase (can be set up in the Android hotspot settings). This connection works fine, if I connect the client phone (Android 10) to the hotspot via the "Android System Wi-Fi Panel" (tap on Wi-Fi, select hotspot, enter passphrase → connected). My Socket connection can be established - client and server can communicate.
The client phone reports, that there is no internet available within this hotspot, which is ok since I don't want to access its internet connection.
But now, I want to connect directly to it via the WifiManager and a self created WifiConfiguration by using the following code, without going to the Android settings:
public static boolean saveAndConnectToWpaConfig(Context context, String ssidParam, String passphrase)
{
String ssidFormated = "\"" + ssidParam + "\"";
WifiConfiguration wifiConfiguration = new WifiConfiguration();
wifiConfiguration.SSID = ssidFormated;
wifiConfiguration.preSharedKey = "\"" + passphrase + "\"";
wifiConfiguration.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
try {
WifiManager wifiManager = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
int networkId;
if (wifiManager != null) {
for (WifiConfiguration wifi :wifiManager.getConfiguredNetworks()) {
if(wifi.SSID.equals(ssidFormated)) {
wifiManager.removeNetwork(wifi.networkId);
break;
}
}
networkId = wifiManager.addNetwork(wifiConfiguration);
if (networkId != -1)
{
wifiManager.disconnect();
if(wifiManager.enableNetwork(networkId, true)) {
wifiManager.saveConfiguration();
return true;
}
}
}
} catch (Exception e) {
Logs.log(Logs.LogTypes.exception, "Can't connect to SSID: " + ssidParam, e);
}
return false;
}
On the one hand, this code works. I can connect to the hotspot and Android says it's fine. On the other hand, trying to create my socket connection leads now unexpected to a timeout in the createSocket() method:
socket = SSLUtility.getSocketFactory().createSocket(ip, port);
Exception:
java.net.ConnectException: failed to connect to /192.168.43.1 (port 42223) from /:: (port 36660): connect failed: ETIMEDOUT (Connection timed out)
at libcore.io.IoBridge.connect(IoBridge.java:143)
at java.net.PlainSocketImpl.socketConnect(PlainSocketImpl.java:142)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:390)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:230)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:212)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:436)
at java.net.Socket.connect(Socket.java:621)
(The SSLUtility builds a socket factory, but in my opinion, this is not important in that case since this code already works when I connect to the Wifi via the "Android System Wifi Panel")
I inspected the configuration files of both connections:
Working Hotspot connection via "Android System Wifi Panel":
ID: 99 SSID: "My_Hotsport_1234" PROVIDER-NAME: null BSSID: null FQDN: null PRIO: 16 HIDDEN: false PMF: false
NetworkSelectionStatus NETWORK_SELECTION_ENABLED
hasEverConnected: true
numAssociation 1
update millis:1601964892066
creation millis:1601964892066
trusted
macRandomizationSetting: 1
mRandomizedMacAddress: 02:00:00:00:00:00
KeyMgmt: WPA_PSK Protocols: WPA RSN
AuthAlgorithms: OPEN
PairwiseCiphers: TKIP CCMP
GroupCiphers: WEP40 WEP104 TKIP CCMP
GroupMgmtCiphers:
SuiteBCiphers:
PSK/SAE: *
Enterprise config:
eap NULL
phase2 "auth=NULL"
IP config:
IP assignment: DHCP
Proxy settings: NONE
cuid=1000 cname=android.uid.system:1000 luid=1000 lname=android.uid.system:1000 lcuid=1000 userApproved=USER_UNSPECIFIED noInternetAccessExpected=true
recentFailure: Association Rejection code: 0
samsungSpecificFlags:
semAutoWifiScore: 0
isVendorAp : false
recoverableRSSI: -200
inRecoverArea: false
disabledTime: 0
notInRangeTime: 0
validatedInternetAccess: false
skipInternetCheck: -1
notAskAgainCheck: false
nextTargetRssi: 0
isCaptivePortal: false
isAuthenticated: false
loginUrl: null
autoReconnect: 1
isRecommended: false
isHomeProviderNetwork: false
WapiCertIndex: 0
WapiPskType: 0
isWeChatAp : false
semMhsUserName :
entryRssi24GHz : -78
entryRssi5GHz : -75
Programmatically created hotspot connection:
ID: 100 SSID: "My_Hotsport_1234" PROVIDER-NAME: null BSSID: null FQDN: null PRIO: 17 HIDDEN: false PMF: false
NetworkSelectionStatus NETWORK_SELECTION_ENABLED
hasEverConnected: true
numAssociation 1
numNoInternetAccessReports 1
update millis:1601965132465
creation millis:1601965132465
trusted
macRandomizationSetting: 1
mRandomizedMacAddress: 02:00:00:00:00:00
KeyMgmt: WPA_PSK WPA_EAP Protocols: WPA RSN
AuthAlgorithms: OPEN
PairwiseCiphers: TKIP CCMP
GroupCiphers: WEP40 WEP104 TKIP CCMP
GroupMgmtCiphers:
SuiteBCiphers:
PSK/SAE: *
Enterprise config:
eap NULL
phase2 "auth=NULL"
IP config:
IP assignment: DHCP
Proxy settings: NONE
cuid=10463 cname=com.myCompany.myAppName luid=10463 lname=com.myCompany.myAppName lcuid=10463 userApproved=USER_UNSPECIFIED noInternetAccessExpected=false
recentFailure: Association Rejection code: 0
samsungSpecificFlags:
semAutoWifiScore: 0
isVendorAp : false
recoverableRSSI: -200
inRecoverArea: false
disabledTime: 0
notInRangeTime: 0
validatedInternetAccess: false
skipInternetCheck: -1
notAskAgainCheck: false
nextTargetRssi: 0
isCaptivePortal: false
isAuthenticated: false
loginUrl: null
autoReconnect: 1
isRecommended: false
isHomeProviderNetwork: false
WapiCertIndex: 0
WapiPskType: 0
isWeChatAp : false
semMhsUserName :
entryRssi24GHz : -78
entryRssi5GHz : -75
The two differences are:
numNoInternetAccessReports
flag which is not in the self created config availableNow my questions:
-Djavax.net.debug=all
to get the output, how is this in Android possible?I recognized that an Android dialog opens, which notify that there is no internet connection using this hotspot when I'm connecting to it in the Android Settings. With my self created configuration, it won't appear.
Finally I got it.. The problem was indeed the line:
cuid=10463 cname=com.myCompany.myAppName luid=10463 lname=com.myCompany.myAppName lcuid=10463 userApproved=USER_UNSPECIFIED noInternetAccessExpected=false
But it's not regarding the user (my app or the Android system) who added the Hotspot, it's the noInternetAccessExpected
field. Unfortunately, connecting the Hotspot manually doesn't trigger the "don't ask again" dialog (only in my case?) which says that there is no internet available within this hotspot which set this field. I discovered it by pinging the server from the adb shell. Before I closed the dialog, no pin came back, after closing the dialog, it worked.
But you can't set the field in the configuration file since it has no getter/setter -> smells like reflection is necessary:
String ssidFormated = "\"" + ssidParam + "\"";
WifiConfiguration wifiConfiguration = new WifiConfiguration();
wifiConfiguration.SSID = ssidFormated;
wifiConfiguration.preSharedKey = "\"" + passphrase + "\"";
wifiConfiguration.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
try {
Field fieldname = WifiConfiguration.class.getField("noInternetAccessExpected");
if(fieldname != null) {
fieldname.set(wifiConfiguration, true);
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
And voir la - this was the trick. I think normally the dialog should pop up, but in my case it didn't...
Hope this could help someone!