I am wondering if there is any way to get Wi-Fi hotspot status (on or off) in Android Oreo (API 26 and higher) without using reflection, because it will not work on Android P according to the new restrictions on non-sdk interfaces
I've seen that there are some methods that provide the ability to disable a WiFi hotspot using reflection, but I would like to avoid those and simply being able to know if the hotspot is enabled.
Thanks in advance!
Please look at the following code. This will help you
public class WifiApManager {
private final WifiManager mWifiManager;
public WifiApManager(Context context) {
mWifiManager = (WifiManager)context.getSystemService(Context.WIFI_SERVICE);
}
/*the following method is for getting the wifi hotspot state*/
public WIFI_AP_STATE getWifiApState() {
try {
Method method = mWifiManager.getClass().getMethod("getWifiApState");
int tmp = ((Integer) method.invoke(mWifiManager));
// Fix for Android 4
if (tmp > 10) {
tmp = tmp - 10;
}
return WIFI_AP_STATE.class.getEnumConstants()[tmp];
} catch (Exception e) {
Log.e(this.getClass().toString(), "", e);
return WIFI_AP_STATE.WIFI_AP_STATE_FAILED;
}
}
/**
* Return whether Wi-Fi Hotspot is enabled or disabled.
*
* #return {#code true} if Wi-Fi AP is enabled
* #see #getWifiApState()
*/
public boolean isWifiApEnabled() {
return getWifiApState() == WIFI_AP_STATE.WIFI_AP_STATE_ENABLED;
}
}
Where WIFI_AP_STATE is an enum which is as follows
public enum WIFI_AP_STATE {
WIFI_AP_STATE_DISABLING,
WIFI_AP_STATE_DISABLED,
WIFI_AP_STATE_ENABLING,
WIFI_AP_STATE_ENABLED,
WIFI_AP_STATE_FAILED
}
Related
I am making an app that gets Wi-Fi and Mobile Data information. The Wi-Fi portion of the app is working fine, but I can't seem to get the data part working. I've heard of issues like this on Samsung phones (I'm testing on one), and I need a workaround without going above my API level of 15.
Here is my current code:
class myPhoneStateListener extends PhoneStateListener {
#Override
public void onSignalStrengthsChanged(SignalStrength signalStrength) {
super.onSignalStrengthsChanged(signalStrength);
if (signalStrength.isGsm()) {
mobileStrength = signalStrength.getGsmSignalStrength();
mobileStrength = (2 * mobileStrength) - 113;
} else {
mobileStrength = signalStrength.getCdmaDbm();
}
}
}
But it returns null.
/**
* Gets the signal level from a <tt>SignalStrength</tt> as a value in the
* range 0-4. This info is hidden from the public API, so this method
* obtains it via reflection.
*
* #return the signal level, or 0 if Google has broken the hack
*/
public static int getSignalLevel(final SignalStrength signal) {
try {
final Method m = SignalStrength.class.getDeclaredMethod("getLevel", (Class[]) null);
m.setAccessible(true);
return (Integer) m.invoke(signal, (Object[]) null);
} catch (Exception e) {
Log.debug(TAG, "Google hates developers", e);
return 0;
}
}
Do you have set the permission in your AndroidManifest.xml file ?
If not, set this to read the phone state.
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
Yours sincerely,
Flemming
I am trying to create an app where one android app can transfer files ( text , video , photo ) to other multiple android devices.initially i thought to use wifi direct in android to share files across multiple devices.
but the problem i am facing with WiFi direct is , its inconsistency in maintaining connection and finding other devices.
1) sometimes app has to wait around 5 mins or more minutes and after that its able to connect.
2) many times after accepting invitation through a dialog from other device, it takes lot of time in changing connection to connected state and till then device is not able to get the IP address of other device.
after experiencing the inconsistency, i thought to drop the idea of using wifi direct. does anyone has a better suggestion to FASTER transfer multiple files from one mobile device to another devices without access points.
Hotspot uses hidden methods which are invoked using Reflection. Essentially, hotspot is an access point to which other people can connect as they connect to normal wifi networks.
As told above it is an access point, hence they are two major functions one needs to support
Creating a hotspot
Connecting to one.
1. Creating a hotspot
/**
* Start AccessPoint mode with the specified
* configuration. If the radio is already running in
* AP mode, update the new configuration
* Note that starting in access point mode disables station
* mode operation
* #param wifiConfig SSID, security and channel details as part of WifiConfiguration
* #return {#code true} if the operation succeeds, {#code false} otherwise
*/
public boolean setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
try {
if (enabled) { // disable WiFi in any case
mWifiManager.setWifiEnabled(false);
}
Method method = mWifiManager.getClass().getMethod("setWifiApEnabled", WifiConfiguration.class, boolean.class);
return (Boolean) method.invoke(mWifiManager, wifiConfig, enabled);
} catch (Exception e) {
Log.e(this.getClass().toString(), "", e);
return false;
}
}
Setting up a hotspot with password (WPA2 in the following example)
WifiConfiguration wifiCon = new WifiConfiguration();
wifiCon.SSID = "ssid";
wifiCon.preSharedKey = "password";
wifiCon.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED);
wifiCon.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
wifiCon.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
wifiCon.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
try
{
Method setWifiApMethod = wm.getClass().getMethod("setWifiApEnabled", WifiConfiguration.class, boolean.class);
boolean apstatus=(Boolean) setWifiApMethod.invoke(wm, wifiCon,true);
}
catch (Exception e)
{
Log.e(this.getClass().toString(), "", e);
}
2. Connecting to a hotspot
public Boolean connectToHotspot(WifiManager wifiManager, String ssid)
{
this.wifiManager = wifiManager;
WifiConfiguration wc = new WifiConfiguration();
wc.SSID = "\"" +encodeSSID(ssid) +"\"";
wc.preSharedKey = "\"" + generatePassword(new StringBuffer(ssid).reverse().toString()) + "\"";
wifiManager.addNetwork(wc);
List<WifiConfiguration> list = wifiManager.getConfiguredNetworks();
for( WifiConfiguration i : list ) {
if(i!=null && i.SSID != null && i.SSID.equals(wc.SSID))
{
wifiManager.disconnect();
boolean status = wifiManager.enableNetwork(i.networkId, true);
wifiManager.reconnect();
return status;
}
}
return false;
}
Coming to think of it, you may also need list of devices connected to hotspot
/**
* Gets a list of the clients connected to the Hotspot, reachable timeout is 300
* #param onlyReachables {#code false} if the list should contain unreachable (probably disconnected) clients, {#code true} otherwise
* #param finishListener, Interface called when the scan method finishes
*/
public void getClientList(boolean onlyReachables, FinishScanListener finishListener) {
getClientList(onlyReachables, 300, finishListener );
}
/**
* Gets a list of the clients connected to the Hotspot
* #param onlyReachables {#code false} if the list should contain unreachable (probably disconnected) clients, {#code true} otherwise
* #param reachableTimeout Reachable Timout in miliseconds
* #param finishListener, Interface called when the scan method finishes
*/
public void getClientList(final boolean onlyReachables, final int reachableTimeout, final FinishScanListener finishListener) {
Runnable runnable = new Runnable() {
public void run() {
BufferedReader br = null;
final ArrayList<String> resultIPAddr = new ArrayList<String>();
try {
br = new BufferedReader(new FileReader("/proc/net/arp"));
String line;
while ((line = br.readLine()) != null) {
String[] splitted = line.split(" +");
if ((splitted != null) && (splitted.length >= 4)) {
// Basic sanity check
String mac = splitted[3];
if (mac.matches("..:..:..:..:..:..")) {
boolean isReachable = InetAddress.getByName(splitted[0]).isReachable(reachableTimeout);
if (!onlyReachables || isReachable) {
resultIPAddr.add(splitted[0]);
}
}
}
}
} catch (Exception e) {
Log.e(this.getClass().toString(), e.toString());
} finally {
try {
br.close();
} catch (IOException e) {
Log.e(this.getClass().toString(), e.getMessage());
}
}
// Get a handler that can be used to post to the main thread
Handler mainHandler = new Handler(context.getMainLooper());
Runnable myRunnable = new Runnable() {
#Override
public void run() {
finishListener.onFinishScan(result);
}
};
mainHandler.post(myRunnable);
}
};
Thread mythread = new Thread(runnable);
mythread.start();
}
Also you may need to scan for nearby Wifi networks to get the network to connect to.
//This can be done by getting WifiManager's instance from the System.
WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
wifiManager.getScanResults();
// The above is an async call and will results are available System will broadcast `SCAN_RESULTS_AVAILABLE` intent and you need to set a `BroadCastReceiver` for it.
// And get the results like this
List<ScanResult> results = wifiManager.getScanResults();
Hope these are all the pointers you need..!!
Wifi direct as a technology is ideal for peer to peer communication.However talking about wifi direct for android , it works well only for a single connection that is only 1-1 use case .It is possible to create a one to many where every device connects to the group owner (Soft AP).But even if u build a one to one and try extend to multi use case you will have problems with certain devices that do no connect perfectly.Devices getting stuck in invited state. Checkout some of the problems listed under problems after downloading this application https://play.google.com/store/apps/details?id=com.budius.WiFiShoot&hl=en
If you want to go for multiple connection it is better to use hotspot .One device ends up being the hotspot and other clients connect to the hotspot .It is being used by plenty of application like xender, zapiya.
I have update my mobile to Android Lollipop, before updating to Lollipop it works fine. Now I am facing problem with network interface.
if (isWifiConnected()) {
Log.d(TAG,"Wifi is connected");
mNetIf = Utils.getActiveNetworkInterface();
String name = mNetIf.getName();
Log.d(TAG, "network interface in constructor" + NetworkInterface.getByName(name));
//do some multicast Operations.
}
If the WiFi is connected I should do some multicast operation in WiFi.
iswifiConnected method
public boolean isWifiConnected(){
ConnectivityManager connManager = (ConnectivityManager)mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo mWifi = connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
if (mWifi.isConnected()) {
return true;
}
return false;
}
Utils.getActiveNetworkInterface
public static NetworkInterface getActiveNetworkInterface() {
Enumeration<NetworkInterface> interfaces = null;
try {
interfaces = NetworkInterface.getNetworkInterfaces();
} catch (SocketException e) {
return null;
}
while (interfaces.hasMoreElements()) {
NetworkInterface iface = interfaces.nextElement();
Enumeration<InetAddress> inetAddresses = iface.getInetAddresses();
/* Check if we have a non-local address. If so, this is the active
* interface.
*
* This isn't a perfect heuristic: I have devices which this will
* still detect the wrong interface on, but it will handle the
* common cases of wifi-only and Ethernet-only.
*/
while (inetAddresses.hasMoreElements()) {
InetAddress addr = inetAddresses.nextElement();
if (!(addr.isLoopbackAddress() || addr.isLinkLocalAddress())) {
return iface;
}
}
}
return null;
}
Log
Wifi is connected
network interface in constructor**[rmnet0][3]t** [/fe80::32e3:daf0:ba51:f971%rmnet0%3][/27.57.104.11]//3g network interface
I am wondering how the app got 3g interface. It should get wlan interface, it work in all other mobile. Is it a bug?
Permissions:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
You are using the ConnectivityManger but, to use the WiFi network in Android, the best choice is to use the WifiManager: it has many features dedicated to Wifi. In particular, if you want to get a NetworkInterface object referencing the WiFi Interface, you can use the following method:
public static NetworkInterface getActiveWifiInterface(Context context) throws SocketException, UnknownHostException {
WifiManager wifiManager = (WifiManager)context.getSystemService(Context.WIFI_SERVICE);
//Return dynamic information about the current Wi-Fi connection, if any is active.
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
if(wifiInfo == null) return null;
InetAddress address = intToInet(wifiInfo.getIpAddress());
return NetworkInterface.getByInetAddress(address);
}
public static byte byteOfInt(int value, int which) {
int shift = which * 8;
return (byte)(value >> shift);
}
public static InetAddress intToInet(int value) {
byte[] bytes = new byte[4];
for(int i = 0; i<4; i++) {
bytes[i] = byteOfInt(value, i);
}
try {
return InetAddress.getByAddress(bytes);
} catch (UnknownHostException e) {
// This only happens if the byte array has a bad length
return null;
}
}
I think the problem is that getInetAddresses() returns a list of interfaces, and getActiveNetworkInterface is only returning the first one no matter what.
And so the interface you are getting depends on the order of the list which getInetAddresses() returns.
That being said, one of the solutions could be: look at the up interface, using isUp().
http://developer.android.com/reference/java/net/NetworkInterface.html#isUp()
Android would turn off the cellular connection to save power when connected to wifi networks, so by looking at only the UP interface, you should able to pin point the WiFi interface.
I want to know how to detect state of WiFi tethering. I've seen an article: Android 2.3 wifi hotspot API But it doesn't work! It returns always WIFI_AP_STATE_DISABLED = 1. It doesn't depend on real state of WiFi tethering.
Using reflection:
WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
Method[] wmMethods = wifi.getClass().getDeclaredMethods();
for (Method method: wmMethods) {
if (method.getName().equals("isWifiApEnabled")) {
try {
boolean isWifiAPenabled = method.invoke(wifi);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
As you can see here
In addition to the reflexion, to get the Wifi tethering status update, you can listen to this broadcast Action :
IntentFilter filter = new IntentFilter("android.net.wifi.WIFI_AP_STATE_CHANGED");
To get all tethering option update :
IntentFilter filter = new IntentFilter("android.net.conn.TETHER_STATE_CHANGED");
Those actions are hidden inside the Android source code
First, you need to get WifiManager:
Context context = ...
final WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
Then:
public static boolean isSharingWiFi(final WifiManager manager)
{
try
{
final Method method = manager.getClass().getDeclaredMethod("isWifiApEnabled");
method.setAccessible(true); //in the case of visibility change in future APIs
return (Boolean) method.invoke(manager);
}
catch (final Throwable ignored)
{
}
return false;
}
Also you need to request a permission in AndroidManifest.xml:
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
Here is the Xamarin C# version if anyone is looking:
static Method isWifiApEnabledMethod;
public static bool IsWifiApEnabled ()
{
var wifiManager = WifiManager.FromContext (Application.Context);
if (isWifiApEnabledMethod == null)
{
try
{
isWifiApEnabledMethod = wifiManager.Class.GetDeclaredMethod ("isWifiApEnabled");
isWifiApEnabledMethod.Accessible = true; //in the case of visibility change in future APIs
}
catch (NoSuchMethodException e)
{
Debug.WriteLine ("Can't get method by reflection" + e);
}
catch (System.Exception ex)
{
Debug.WriteLine ("Can't get method by reflection" + ex);
}
}
if (isWifiApEnabledMethod != null)
{
try
{
return (bool)isWifiApEnabledMethod.Invoke (wifiManager);
}
catch (System.Exception ex)
{
Debug.WriteLine ("Can't invoke by reflection" + ex);
}
}
return false;
}
(without using reflection since they say google is restricting it)
I'm writting this answer 10 years later. also I don't know if this can be considered a good aproach or not but I first get the Wlan network interface IPs
and if there is no address I assume that it tethering isn't enabled. if there is an address, I check using the connectivity manger whether WI-FI is connected to a network or not. if there is an IP for the Wlan network interface but it isn't connected to a network, I assume tethering is enabled.
you probably would need to add this line to your manifest file
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
code to get the ip of an inteface (this only gets the IPv4, you can modify it to get the IPv6 or both if you want)
// method used to retrieve Wlan ip addresses IPv4 of the device.
public static String IpAddresses() throws NoAddressFoundException, SocketException {
Enumeration<NetworkInterface> Nics = NetworkInterface.getNetworkInterfaces();
while (Nics.hasMoreElements()) {
NetworkInterface NIC = Nics.nextElement();
if (NIC.isUp() && !NIC.isLoopback() && NIC.getName().contains("wlan")) {
Enumeration<InetAddress> Addresses = NIC.getInetAddresses();
while (Addresses.hasMoreElements()) {
InetAddress WlanAddress = Addresses.nextElement();
if (WlanAddress instanceof Inet4Address)
return WlanAddress.getHostAddress();
}
}
}
throw new NoAddressFoundException("No suitable wifi address found");
}
then if there is an address i check if wifi is connected by this method:
//method to check if the device is connected to a Wi-Fi network; it doesn't matter if network has access to internet
public static boolean isWifiConnected(Context context) {
ConnectivityManager ConMan = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo WifiInfo = ConMan.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
return WifiInfo.isConnected();
}
NOTE: the "NoAddressFoundException" is a custom exception in my app if anyone is wondering. it won't exist in your case.
Reflection is a poor way to achieve this.
We can inspect the DhcpInfo to determine if the device is allocating addresses (mobile hotspot) or is being allocated by another DHCP server.
Here is a kotlin function that will determine if a device is a mobile hotspot, it has not been widely tested so YMMV.
fun isMobileHotspot(manager: WifiManager): Boolean {
val info = manager.dhcpInfo
return (
info.ipAddress == 0
&& info.netmask == 0
&& info.gateway == 0
&& info.serverAddress == 16885952) // 192.168.1.1
}
I have a wifi LAN setup which does not have internet access. Just various other local wifi devices connected to it. The DHCP is configured to not return a gateway or dns server. Only an IP and netmask.
When I connect my android to this wifi AP it connects fine, but all internet connectivity on the phone stops working.
I would expect that since the wifi has no gateway setting that android should realize the internet can't go through that connection and should instead be routed through the 3G connection which is at 5 bars.
I've tried setting a static IP on the android phone as well, but this did not help.
The main reason for this setup is so that the android device can transfer data on this remote network to an internet based server since it can connect to the local devices without issue. However the 3G side is broken once the wifi is setup.
Any thoughts on how to work around this issue?
After a bit of coding and testing I have merged Squonk and this solution. This is the class I have created:
package it.helian.exampleprj.network;
import java.net.InetAddress;
import java.net.UnknownHostException;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo.State;
import android.net.wifi.WifiManager;
import android.text.TextUtils;
import android.util.Log;
public class NetworkUtils {
private static final String TAG_LOG = "ExamplePrj";
Context context;
WifiManager wifiMan = null;
WifiManager.WifiLock wifiLock = null;
public NetworkUtils(Context context) {
super();
this.context = context;
}
/**
* Enable mobile connection for a specific address
* #param context a Context (application or activity)
* #param address the address to enable
* #return true for success, else false
*/
public boolean forceMobileConnectionForAddress(Context context, String address) {
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (null == connectivityManager) {
Log.d(TAG_LOG, "ConnectivityManager is null, cannot try to force a mobile connection");
return false;
}
//check if mobile connection is available and connected
State state = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState();
Log.d(TAG_LOG, "TYPE_MOBILE_HIPRI network state: " + state);
if (0 == state.compareTo(State.CONNECTED) || 0 == state.compareTo(State.CONNECTING)) {
return true;
}
//activate mobile connection in addition to other connection already activated
int resultInt = connectivityManager.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, "enableHIPRI");
Log.d(TAG_LOG, "startUsingNetworkFeature for enableHIPRI result: " + resultInt);
//-1 means errors
// 0 means already enabled
// 1 means enabled
// other values can be returned, because this method is vendor specific
if (-1 == resultInt) {
Log.e(TAG_LOG, "Wrong result of startUsingNetworkFeature, maybe problems");
return false;
}
if (0 == resultInt) {
Log.d(TAG_LOG, "No need to perform additional network settings");
return true;
}
//find the host name to route
String hostName = extractAddressFromUrl(address);
Log.d(TAG_LOG, "Source address: " + address);
Log.d(TAG_LOG, "Destination host address to route: " + hostName);
if (TextUtils.isEmpty(hostName)) hostName = address;
//create a route for the specified address
int hostAddress = lookupHost(hostName);
if (-1 == hostAddress) {
Log.e(TAG_LOG, "Wrong host address transformation, result was -1");
return false;
}
//wait some time needed to connection manager for waking up
try {
for (int counter=0; counter<30; counter++) {
State checkState = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState();
if (0 == checkState.compareTo(State.CONNECTED))
break;
Thread.sleep(1000);
}
} catch (InterruptedException e) {
//nothing to do
}
boolean resultBool = connectivityManager.requestRouteToHost(ConnectivityManager.TYPE_MOBILE_HIPRI, hostAddress);
Log.d(TAG_LOG, "requestRouteToHost result: " + resultBool);
if (!resultBool)
Log.e(TAG_LOG, "Wrong requestRouteToHost result: expected true, but was false");
state = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState();
Log.d(TAG_LOG, "TYPE_MOBILE_HIPRI network state after routing: " + state);
return resultBool;
}
/**
* This method extracts from address the hostname
* #param url eg. http://some.where.com:8080/sync
* #return some.where.com
*/
public String extractAddressFromUrl(String url) {
String urlToProcess = null;
//find protocol
int protocolEndIndex = url.indexOf("://");
if(protocolEndIndex>0) {
urlToProcess = url.substring(protocolEndIndex + 3);
} else {
urlToProcess = url;
}
// If we have port number in the address we strip everything
// after the port number
int pos = urlToProcess.indexOf(':');
if (pos >= 0) {
urlToProcess = urlToProcess.substring(0, pos);
}
// If we have resource location in the address then we strip
// everything after the '/'
pos = urlToProcess.indexOf('/');
if (pos >= 0) {
urlToProcess = urlToProcess.substring(0, pos);
}
// If we have ? in the address then we strip
// everything after the '?'
pos = urlToProcess.indexOf('?');
if (pos >= 0) {
urlToProcess = urlToProcess.substring(0, pos);
}
return urlToProcess;
}
/**
* Transform host name in int value used by {#link ConnectivityManager.requestRouteToHost}
* method
*
* #param hostname
* #return -1 if the host doesn't exists, elsewhere its translation
* to an integer
*/
private int lookupHost(String hostname) {
InetAddress inetAddress;
try {
inetAddress = InetAddress.getByName(hostname);
} catch (UnknownHostException e) {
return -1;
}
byte[] addrBytes;
int addr;
addrBytes = inetAddress.getAddress();
addr = ((addrBytes[3] & 0xff) << 24)
| ((addrBytes[2] & 0xff) << 16)
| ((addrBytes[1] & 0xff) << 8 )
| (addrBytes[0] & 0xff);
return addr;
}
#SuppressWarnings("unused")
private int lookupHost2(String hostname) {
InetAddress inetAddress;
try {
inetAddress = InetAddress.getByName(hostname);
} catch (UnknownHostException e) {
return -1;
}
byte[] addrBytes;
int addr;
addrBytes = inetAddress.getAddress();
addr = ((addrBytes[3] & 0xff) << 24)
| ((addrBytes[2] & 0xff) << 16)
| ((addrBytes[1] & 0xff) << 8 )
| (addrBytes[0] & 0xff);
return addr;
}
public Boolean disableWifi() {
wifiMan = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
if (wifiMan != null) {
wifiLock = wifiMan.createWifiLock(WifiManager.WIFI_MODE_SCAN_ONLY, "HelianRCAWifiLock");
}
return wifiMan.setWifiEnabled(false);
}
public Boolean enableWifi() {
Boolean success = false;
if (wifiLock != null && wifiLock.isHeld())
wifiLock.release();
if (wifiMan != null)
success = wifiMan.setWifiEnabled(true);
return success;
}
}
This is the usage:
USAGE CODE
boolean mobileRoutingEnabled = checkMobileInternetRouting();
if(!mobileRoutingEnabled) {
networkUtils.disableWifi();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
networkUtils.forceMobileConnectionForAddress(context, RCA_URL);
if(!mobileRoutingEnabled) {
networkUtils.enableWifi();
}
// This second check is for testing purpose
checkMobileInternetRouting();
return callWebService(RCA_COMPLETE_URL, _plate);
where checkMobileInternetRouting is:
private boolean checkMobileInternetRouting() {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
State state = cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState();
return 0 == state.compareTo(State.CONNECTED) || 0 == state.compareTo(State.CONNECTING);
}
USAGE PROCEDURE
Check if the routing to the host is enabled
If yes go with the communication regardless the wifi is connected or not and execute only points 6 (the point 4 will only check that routing is already enable without executing any rilevant action). Otherwise temporary disables the wifi.
Thread sleep of about 3 seconds for letting the 3g connection comes back
Set the 3g routing to the given url
Enable back the wifi
Now the given url can be called even with a wifi connection without net acces
CONCLUSIONS
This is a bit hacky but works properly. The only problem is that this routing has got a timeout of few seconds (like 20-30) that forces you to execute the entire above procedure once more. Setting this timeout to a higher value would be very good.
Google added some useful methods in Android SDK 21 for this purpose.
You can create NetworkRequest:
NetworkRequest networkRequest = new NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.build();
And then you can request such network using ConnectivityManager. For example, you want to be sure that all HTTP requests will be passed through the network with internet access. You can build your Retrofit API in this way:
ApiConfig apiConfig;
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
connectivityManager.requestNetwork(networkRequest, new ConnectivityManager.NetworkCallback() {
#Override
public void onAvailable(Network network) {
apiConfig = new Retrofit.Builder()
.baseUrl("https://api.imatrix.io/")
.client(new OkHttpClient.Builder()
.socketFactory(network.getSocketFactory())
.build())
.build()
.create(ApiConfig.class);
}
#Override
public void onLost(Network network) {
apiConfig = null;
}
});
Please, mind the thread-safety when you're using such snippet of code.
In addition, I suggest check ConnectivityManager#bindProcessToNetwork and this blog.
ConnectivityManager.NetworkCallback is an empty class and it has several methods.
From code, when you detect there is no connectivity, you could switch off WiFi...
As for a setting, there is none (no good way to check if there really is connectivity universally and reliably). But some phones do just what you describe automatically, like for example my LG P-970.
(Note: Android disconnects from mobile networks when it connects to a WiFi, so there is no way to still be connected to a WiFi but route internet access through mobile, even though Linux can do it (with the ip route ... suite of tools))
I can't guarantee this will work as it's something I only experimented with some time ago. I had a similar need to use 3G (or other mobile network) when the wifi-connected network had no route to the outside world.
The following code should drop the wifi connection in order to allow the mobile network to come in to play. You'll need to do various tests along the way and re-establish the wifi connection again afterwards...
WifiManager wifiMan = null;
WifiManager.WifiLock wifiLock = null;
private Boolean disableWifi() {
wifiMan = (WifiManager) getSystemService(Context.WIFI_SERVICE);
if (wifiMan != null) {
wifiLock = wifiMan.createWifiLock(WifiManager.WIFI_MODE_SCAN_ONLY, "MyWifiLock");
}
return wifiMan.setWifiEnabled(false);
}
private Boolean enableWifi() {
Boolean success;
if (wifiLock != null)
wifiLock.release();
if (wifiMan != null)
success = wifiMan.setWifiEnabled(true);
return success;
}
you don't need to code anything. i found an app that do exactly this thing. you can configure to disconnect automatically from the wifi if there is no internet from this connection.
https://play.google.com/store/apps/details?id=com.nLabs.internetconnectivity&hl=en