Android L (5.x) Turn ON/OFF "Mobile Data" programmatically - android

I need to Turn ON/OFF Mobile data programmatically. Below code is not working for 5.x. Can you please help me. Thanks in advance.
private void setMobileDataEnabled(Context context, boolean enabled) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
final ConnectivityManager conman = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
final Class conmanClass = Class.forName(conman.getClass().getName());
final Field connectivityManagerField = conmanClass.getDeclaredField("mService");
connectivityManagerField.setAccessible(true);
final Object connectivityManager = connectivityManagerField.get(conman);
final Class connectivityManagerClass = Class.forName(connectivityManager.getClass().getName());
final Method setMobileDataEnabledMethod = connectivityManagerClass.getDeclaredMethod("setMobileDataEnabled", Boolean.TYPE);
setMobileDataEnabledMethod.setAccessible(true);
setMobileDataEnabledMethod.invoke(connectivityManager, enabled); }
03-30 12:42:29.466: W/System.err(5966):
java.lang.NoSuchMethodException: setMobileDataEnabled [boolean] 03-30
12:42:29.466: W/System.err(5966): at
java.lang.Class.getMethod(Class.java:664) 03-30 12:42:29.466:
W/System.err(5966): at
java.lang.Class.getDeclaredMethod(Class.java:626)
java.lang.NoSuchMethodException: setMobileDataEnabled [boolean] # below line.
final Method setMobileDataEnabledMethod =
connectivityManagerClass.getDeclaredMethod("setMobileDataEnabled",
Boolean.TYPE);

It seems like the setMobileDataEnabled method no longer exists in
ConnectivityManager and this functionality was moved to
TelephonyManager with two methods getDataEnabled and setDataEnabled.
public void setMobileDataState(boolean mobileDataEnabled)
{
try
{
TelephonyManager telephonyService = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
Method setMobileDataEnabledMethod = telephonyService.getClass().getDeclaredMethod("setDataEnabled", boolean.class);
if (null != setMobileDataEnabledMethod)
{
setMobileDataEnabledMethod.invoke(telephonyService, mobileDataEnabled);
}
}
catch (Exception ex)
{
Log.e(TAG, "Error setting mobile data state", ex);
}
}
public boolean getMobileDataState()
{
try
{
TelephonyManager telephonyService = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
Method getMobileDataEnabledMethod = telephonyService.getClass().getDeclaredMethod("getDataEnabled");
if (null != getMobileDataEnabledMethod)
{
boolean mobileDataEnabled = (Boolean) getMobileDataEnabledMethod.invoke(telephonyService);
return mobileDataEnabled;
}
}
catch (Exception ex)
{
Log.e(TAG, "Error getting mobile data state", ex);
}
return false;
}
When executing the code you get a SecurityException stating that Neither user 10089 nor current process has android.permission.MODIFY_PHONE_STATE.
A permission MODIFY_PHONE_STATE should be added
I got this from Answer
Thank you Muzikant

In Android L 5.xx the hidden API setMobileDataEnabled method is removed and it can no longer be used. You can verify this in android lolipop source code under /frameworks/base/core/java/android/net/ConnectivityManager.java.
If you still insist to perform it, you can use code snippet answered by Kushal but getDataEnabled is a system api, which normal user applications cant access. There is also one more system api available setDataEnabled under TelephonyManager. (/frameworks/base/telephony/java/android/telephony/TelephonyManager.java)
/** #hide */
#SystemApi
public void setDataEnabled(boolean enable) {
setDataEnabled(SubscriptionManager.getDefaultDataSubId(), enable);
}
It also needs the permission "android.permission.MODIFY_PHONE_STATE" which will work only on rooted devices.

Quick response, it is not possible to enable/disable mobile data by programming as it is possible with bluetooth.
Starting from version 23 of android, data protection begins to be highly valued and also the protection that an application activates or disables something on the phone, for this reason the permissions are implemented, taking this into account
Starting from this, google proposes that you encourage the user to do this action, giving him context and why he needs to have it activated.
Redirect the user to activate the data
Intent intent = new Intent(Settings.ACTION_DATA_USAGE_SETTINGS);
startActivity(intent);
Redirect the user to activate gps
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(intent);
Request enable Bluetooth
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(intent);

Related

Turning ethernet on and off on android

Is there a way to turn ethernet on and off programatically, similarly to how WiFi can be turned on and off through the WiFiManager class? I believe ifconfig down/up will not work as it would require root. I treid doing ifconfig wlan0 down in a terminal emulator, which gave me permission denied.
I'm on a non-rooted device.
firstly, you should know, since android Q, WifiManager class is not worked.
This method was deprecated in API level 29.
Starting with Build.VERSION_CODES#Q, applications are not allowed to enable/disable Wi-Fi. Compatibility Note: For applications targeting Build.VERSION_CODES.Q or above, this API will always return false and will have no effect. If apps are targeting an older SDK ( Build.VERSION_CODES.P or below), they can continue to use this API.
Both for the network and wifi, I suggest you show a permission dialog, let the user open it, it matches the android permission manager.
you can use the following code to open the setting
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.setComponent(new ComponentName("com.android.settings",
"com.android.settings.Settings$DataUsageSummaryActivity"));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
if the target SDK below Q, you can try to use the reflect way.
private void setMobileDataEnabled(Context context, boolean enabled) throws Exception{
final ConnectivityManager conman = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
Class conmanClass = null;
try {
conmanClass = Class.forName(conman.getClass().getName());
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
final Field iConnectivityManagerField = conmanClass.getDeclaredField("mService");
iConnectivityManagerField.setAccessible(true);
final Object iConnectivityManager = iConnectivityManagerField.get(conman);
final Class iConnectivityManagerClass = Class.forName(iConnectivityManager.getClass().getName());
final Method setMobileDataEnabledMethod = iConnectivityManagerClass.getDeclaredMethod("setMobileDataEnabled", Boolean.TYPE);
setMobileDataEnabledMethod.setAccessible(true);
setMobileDataEnabledMethod.invoke(iConnectivityManager, enabled);
}

Enable mobile data (Lte/3g/gprs) with intent

In my app i want to navigate user to settings where he/she able to activate device mobile data.
I want to use intent to solve this but my problem is that mobile data option is in different pages in device settings for Exmaple below code work fine in Sony Xperia Z2 device (with android 5.1.1)
startActivity(new Intent(Settings.ACTION_WIRELESS_SETTINGS));
But in some other device such as sony experia SP (android 4.3) and samsung S4 (android 5.0.1) user must choose one more step and go to mobile network page.
I can resolve this problem with this code : (Going straight to mobile network)
Intent intent=new Intent(Settings.ACTION_DATA_ROAMING_SETTINGS);
ComponentName cn = new ComponentName("com.android.phone","com.android.phone.Settings");
intent.setComponent(cn);
startActivity(intent);
But user with z2 must return one step back !
How can i resolve this ? choose which way ? (I hope explain problem clear )
try this way:
Also add the permission
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
method to enable mobile/3g data:
private void setMobileDataEnabled(Context context, boolean enabled) {
final ConnectivityManager conman = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
final Class conmanClass = Class.forName(conman.getClass().getName());
final Field iConnectivityManagerField = conmanClass.getDeclaredField("mService");
iConnectivityManagerField.setAccessible(true);
final Object iConnectivityManager = iConnectivityManagerField.get(conman);
final Class iConnectivityManagerClass = Class.forName(iConnectivityManager.getClass().getName());
final Method setMobileDataEnabledMethod = iConnectivityManagerClass.getDeclaredMethod("setMobileDataEnabled", Boolean.TYPE);
setMobileDataEnabledMethod.setAccessible(true);
setMobileDataEnabledMethod.invoke(iConnectivityManager, enabled);
}
For lollipop and above:
The setMobileDataEnabled method is no longer callable as of Android L and later

Cancelling upcoming phone call in android

I making a phone call cancel app. Basically it cancel a upcoming call if your phone is in back position in table or ground (Accelerometer Data). I make a Broadcast Receiver and entry it on the manifest also gave action this android.intent.action.PHONE_STATE
public class PhoneCallReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
Intent si=new Intent(context, MyService.class);
context.startService(si);
TelephonyManager telephony = (TelephonyManager)
context.getSystemService(Context.TELEPHONY_SERVICE);
try {
Class c = Class.forName(telephony.getClass().getName());
Method m = c.getDeclaredMethod("getITelephony");
m.setAccessible(true);
telephonyService = (ITelephony) m.invoke(telephony);
//telephonyService.silenceRinger();
telephonyService.endCall();
Log.e("in try catch", "yes");
Log.e("in try catch", "call cancel");
shrededit.putInt("newcallingstate", 0);
shrededit.commit();
context.stopService(si);
} catch (Exception e) {
e.printStackTrace();
}
Log.e("pr", "out side true block");
}
}
My code is running very well if i only use this code without the accelerometer service class but when i use accelerometer class and make a intent before this below code. My app not canceling the call or not giving any type or error. I think it but not completely sure it is context problem.
So please help me.
No,its not context problem all this code is perfectly fine you does just need a condition or use sharedpreferences for condition.
first make a sharedpreferences object in your service class or that which you show in intent. like this
SharedPreferences sharedpref=this.getSharedPreferences("your_file_name",Context.MODE_PRIVATE);
SharedPreferences.Editor sharededit=sharedpref.edit();
sharededit.putBoolean("String_name", true);
sharededit.commit();
Here boolean is not important you can choose and other data type it depends you.
Then in you Broadcast receiver class you have to again use these SharedPreference and SharedPreference.Editor function and you get the previous boolean value by this method
boolean value=sharededit.getBoolean("callingStop", true);
Than make a condition like this
if(value==true){TelephonyManager telephony = (TelephonyManager)
context.getSystemService(Context.TELEPHONY_SERVICE);
try {
Class c = Class.forName(telephony.getClass().getName());
Method m = c.getDeclaredMethod("getITelephony");
m.setAccessible(true);
telephonyService = (ITelephony) m.invoke(telephony);
//telephonyService.silenceRinger();
telephonyService.endCall();
} catch (Exception e) {
e.printStackTrace();
} }
This is all now your code is run without any error.

Android BroadCastReceiver and android.intent.action.PHONE_STATE Event

I am catching the android.intent.action.PHONE_STATE change event by using following code snippet with android BroadCastReceiver. I could recognize the event successfully and handle the incoming calls also can be done by following code.
My requirement is identifying calls which are coming form a particular number, end that call through the code and invoke a web service for that incoming event.
In here this code runs twice for call receiving and ending events.
I want to stop calling this method for twice. How can i stop calling that code snippet for the second event (ending the call). It would be great-full if any one can help me on this.
if (intent.getAction().equals(
"android.intent.action.PHONE_STATE")) {
Log.i("INFO", "Call Received");
try {
TelephonyManager telephony = (TelephonyManager) context
.getSystemService(Context.TELEPHONY_SERVICE);
Bundle bundle = intent.getExtras();
Log.i("Calling database", "Creatinng DataHandler Object");
DatabaseHandler db = new DatabaseHandler(context);
String phoneNumber =db.getContact().getPhoneNumber();
Log.i("Retriving : ", "Retriving .."+ db.getContact().getPhoneNumber());
if ((bundle.getString("incoming_number").equals(phoneNumber))) {
Log.i("Test Call", "This is the test call");
#SuppressWarnings("rawtypes")
Class c = Class.forName(telephony.getClass().getName());
Method m = c.getDeclaredMethod("getITelephony");
m.setAccessible(true);
ITelephony telephonyService = (ITelephony) m
.invoke(telephony);
telephonyService = (ITelephony) m.invoke(telephony);
telephonyService.endCall();
// Call the web service and send log details
ServiceClient sc = new ServiceClient();
sc.serviceCall(context);
} else {
Log.i("Normal Call", "This is not the test call");
}
} catch (Exception e) {
Log.i("Exception Occured", "Exception in call code snipet");
}
}
}
I believe the issue you are having is that the phone state changes twice, once when the phone rings, then, after you end the call, when the phone goes idle.
You only want this code to run once so the best way to do that is to add an additional check of the phone state to see if it is ringing, if the phone is ringing then end the call.
This can be accomplished by adding the following the check:
if (intent.getAction().equals(
"android.intent.action.PHONE_STATE")) {
Log.i("INFO", "Call Received");
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
if (state.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
//your code here that starts with try block
}
Hope that helps
you can try doing something like this as soon as the receiver starts:
Bundle bundle = nIntent.getExtras();
String phoneNr= bundle.getString("incoming_number");
if(null == phoneNr)
{ // this is outgoing call so bail out
return;
}
You cannot terminate incoming call using third party application due to android security reason. Check in "android application development cookbook" page number "164 "
I know it's too late but I found a batter solution for this.
This normally happens on 5.0 and 5.1. You cannot stop it from calling twice but you can have a universal check to do all your work at one point. And this solution universally work on all OS.
Here is the code
public void onReceive(Context context, Intent intent) {
Object obj = intent.getExtras().get("subscription");
long subId;
if(obj == null) {
subId = Long.MIN_VALUE; // subscription not in extras
} else {
subId = Long.valueOf(obj.toString()); // subscription is long or int
}
if(subId < Integer.MAX_VALUE) {
// hurray, this is called only once on all operating system versions!
}}
for more info check this link.

ANDROID: if WiFi is enabled AND active, launch an intent

This is what I would like to do :
=> IF WiFi is enabled AND active, launch an intent (in fact it's a WebView that gets its content=>the instructions of my app on the web)
=> IF NOT, then I would launch another intent so that I don't show a WebView with "Web page not available ... The Web page at http://www.mywebsite.com might be temporarily down or it may have moved ..."
I tought initially to use
if(wifi.isWifiEnabled())
but that does not say if the Wifi connection is ACTIVE or not. It says only that the user has turned the switch on. The device may or may not be connected... Is this correct ?
Then I tried to use :
if (wifi.getConnectionInfo().getSSID()!= null)
but I noticed that it returns a string even if the connection has been lost or has been disabled ... ?
How should I do then ?
wifi = (WifiManager)getSystemService(Context.WIFI_SERVICE);
Intent intent_instructions;
if (wifi.getConnectionInfo().getSSID()!= null){
Log.i("Hub", "WiFi is enabled AND active !");
Log.i("Hub", "SSID = "+wifi.getConnectionInfo().getSSID());
intent_instructions = new Intent(this, Instructions.class);
}else{
Log.i("Hub", "NO WiFi");
intent_instructions = new Intent(this, Instructions_No_WiFi.class);
}
this.startActivity(intent_instructions);
Is there a more general way to test if the device has the connectivity to the internet just before launching an intent ? be it through Wifi, 3G, etc ...
Thanks in advance for your help.
You can use the following code to check for connectivity:
private static boolean isConnected(Context context) {
ConnectivityManager connectivityManager = (ConnectivityManager)
context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = null;
if (connectivityManager != null) {
networkInfo =
connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
}
return networkInfo == null ? false : networkInfo.isConnected();
}
Please make sure that you've registered the android.net.conn.CONNECTIVITY_CHANGE intent in your Manifest, or else, you'll never receive a notification that you're online.
I've been struggling with this issue for the last couple of days and I just now realized that I needed to register CONNECTIVITY_CHANGE and not only WIFI_STATE_CHANGED.
Try android.net.ConnectivityManager.getActiveNetworkInfo(): if it returns null you have no connection; if it returns a NetworkInfo object, you can check the connection's state with NetworkInfo.getState(), and if it's NetworkInfo.State.CONNECTED then you're connected, else you're not.
You can do it as follows:
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)){
Log.d("WIFI", "WIFI has changed");
int wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, -1);
Log.d("WIFI", "WIFI State = " + wifiState);
setCurrentWifiState(wifiState);
}
You will get 0,1,2,3 depending on which state the Wifi is in, so for example 2 is connecting, you can check the rest in the documents
In your BroadcastReceiver class:
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION)){
boolean connected = intent.getBooleanExtra(WifiManager.EXTRA_SUPPLICANT_CONNECTED, false);
if (connected){
// start your service here
}
}
}
And in your AndroidManifest.xml make sure you register for the android.net.wifi.supplicant.CONNECTION_CHANGE broadcast intent.
<intent-filter >
<action android:name="android.net.wifi.supplicant.CONNECTION_CHANGE" />
</intent-filter>
isConnected() doesnt work fully ok, research something else
final ConnectivityManager connMgr = (ConnectivityManager)
this.getSystemService(Context.CONNECTIVITY_SERVICE);
final android.net.NetworkInfo wifi =
connMgr.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
final android.net.NetworkInfo mobile =
connMgr.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
if( wifi.isAvailable() && wifi.getDetailedState() == DetailedState.CONNECTED){
Toast.makeText(this, "Wifi" , Toast.LENGTH_LONG).show();
}
else if( mobile.isAvailable() && mobile.getDetailedState() == DetailedState.CONNECTED ){
Toast.makeText(this, "Mobile 3G " , Toast.LENGTH_LONG).show();
}
else
{
Toast.makeText(this, "No Network " , Toast.LENGTH_LONG).show();
}
this code check if you are with wifi or 3g or nothing , in the case of wifi on but not connected to a net or 3g have signal problem it detect this details, with DetailedStates

Categories

Resources