Skip to content

Instantly share code, notes, and snippets.

@mikedawson
Last active July 21, 2019 12:24
Show Gist options
  • Save mikedawson/b4f4175613d1ca9bddb2b4dccbb761c9 to your computer and use it in GitHub Desktop.
Save mikedawson/b4f4175613d1ca9bddb2b4dccbb761c9 to your computer and use it in GitHub Desktop.
Android connect to WiFi with no Internet
package com.ustadmobile.port.android.netwokmanager;
import android.annotation.TargetApi;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.NetworkRequest;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.os.Build;
import com.ustadmobile.core.impl.UMLog;
import com.ustadmobile.core.impl.UstadMobileSystemImpl;
import java.util.List;
/**
* Programmatically connect to an Internet AP without Internet, and then
* obtain the Network object to be able to create a SocketFactory or
* open url connections. Android SDK21+ will by default not route any
* traffic via a network without Internet. Alterantively once you obtain
* the network object you could bind the whole app to that network.
*
* Created by mike on 2/9/18.
*/
@TargetApi(21)
public class ConnectWithoutInternetGist {
private Context mContext;
private ConnectivityManager connectivityManager;
private WifiManager wifiManager;
private BroadcastReceiver mWifiBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
switch (intent.getAction()) {
case WifiManager.NETWORK_STATE_CHANGED_ACTION:
NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
boolean isConnected = info.isConnected();
boolean isConnecting = info.isConnectedOrConnecting();
//TODO: probably better to use the EXTRA_ info here
String ssid = wifiManager.getConnectionInfo() != null ?
wifiManager.getConnectionInfo().getSSID() : null;
ssid = normalizeAndroidWifiSsid(ssid);
String stateName = "";
switch (info.getState()) {
case CONNECTED:
stateName = "connected";
break;
case CONNECTING:
stateName = "connecting";
break;
case DISCONNECTED:
stateName = "disconnected";
break;
case DISCONNECTING:
stateName = "disconnecting";
break;
case SUSPENDED:
stateName = "suspended";
break;
case UNKNOWN:
stateName = "unknown";
break;
}
UstadMobileSystemImpl.l(UMLog.DEBUG, 647, "Network: State Changed Action: " +
stateName + " - ssid: " + ssid + " connected:" + isConnected +
" connectedorConnecting: " + isConnecting);
if (Build.VERSION.SDK_INT >= 21) {
if (isConnected) {
NetworkRequest.Builder builder = new NetworkRequest.Builder();
builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
final String connectedSsid = ssid;
connectivityManager.registerNetworkCallback(builder.build(), new ConnectivityManager.NetworkCallback() {
@Override
public void onAvailable(Network network) {
super.onAvailable(network);
NetworkInfo networkInfo = connectivityManager.getNetworkInfo(network);
//This is always the SSID if it's wifi, even though this is *not* documented
String networkSsid = networkInfo.getExtraInfo();
if(networkSsid.equals(connectedSsid)) {
/*
* We can now use network.openURLConnection and network.getSocketFactory()
* to communicate using the wifi network that has no Internet
*/
connectivityManager.unregisterNetworkCallback(this);
}
}
});
}
}
break;
}
}
};
public void init() {
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
mContext.registerReceiver(mWifiBroadcastReceiver, intentFilter);
}
/**
* Android normally but not always surrounds an SSID with quotes on it's configuration objects.
* This method simply removes the quotes, if they are there. Will also handle null safely.
*
* @param ssid
* @return
*/
public static String normalizeAndroidWifiSsid(String ssid) {
if(ssid == null)
return ssid;
else
return ssid.replace("\"", "");
}
/**
* Call this to connect to a wifi network - it will trigger the WIFI_STATE_CHANGED broadcast.
*
* @param ssid
* @param passphrase
*/
public void connectToWifi(String ssid, String passphrase) {
WifiConfiguration wifiConfig = new WifiConfiguration();
wifiConfig.SSID = "\""+ ssid +"\"";
wifiConfig.priority=(getMaxConfigurationPriority(wifiManager)+1);
wifiConfig.preSharedKey = "\""+ passphrase +"\"";
wifiConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
wifiConfig.priority = getMaxConfigurationPriority(wifiManager);
int netId = wifiManager.addNetwork(wifiConfig);
/*
* Note: calling disconnect or reconnect should not be required. enableNetwork(net, true)
* second parameter is defined as boolean enableNetwork (int netId, boolean attemptConnect).
*
* Testing on Android Moto E (2nd gen) Andriod 6.0 the .reconnect() call would cause it to
* reconnect ot the 'normal' wifi because connecting to the group is a bit slow.
*
* This method works without the .reconnect() as tested on Android 4.4.2 Samsung Galaxy ACE
* and Moto E (2nd gen).
*/
wifiManager.disconnect();
boolean successful = wifiManager.enableNetwork(netId, true);
}
/**
* Get maximum priority assigned to a network configuration.
* This helps to prioritize which network to connect to.
*
* @param wifiManager
* @return int: Maximum configuration priority number.
*/
private int getMaxConfigurationPriority(final WifiManager wifiManager) {
final List<WifiConfiguration> configurations = wifiManager.getConfiguredNetworks();
int maxPriority = 0;
for(final WifiConfiguration config : configurations) {
if(config.priority > maxPriority)
maxPriority = config.priority;
}
return maxPriority;
}
}
@3wkit
Copy link

3wkit commented Jul 14, 2019

Can't to connect to hotspot without internet on android Oreo and above?

@mikedawson
Copy link
Author

Can't to connect to hotspot without internet on android Oreo and above?

**It seems like it depends on the device. The code above worked fine on Nokia Android models (running Android 8), but when we tested it with Hauwei devices, it didn't work most of the time.

We changed our approach, we are now using this:

https://github.com/UstadMobile/UstadMobile/blob/dev-kotlin-multi/sharedse/src/main/java/com/ustadmobile/sharedse/network/NetworkManagerBleHelper.java

There is a hidden method that is far more successful (works on all devices that we have tested). The flow in the above java is to call setGroupInfo, then enableWifiNetwork**

@3wkit
Copy link

3wkit commented Jul 21, 2019

I run the code on Xiaomi Redmi Note 6 Pro, Android version 9:
https://github.com/UstadMobile/UstadMobile/blob/dev-kotlin-multi/sharedse/src/main/java/com/ustadmobile/sharedse/network/NetworkManagerBleHelper.java

I can connect to an Internet AP without Internet, but after 1-2 seconds the connection drop down even if there are no any other access point around.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment