I am trying to read WIFI proxy settings
Proxy host
Proxy port
Proxy user (authentication)
Proxy password (authentication)
from devices in android versions 2.X.X – 4.X.X without any success.
Calling:
String proxy = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.HTTP_PROXY);
Always returns null.
I've also added to my android manifest:
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
still it returns null.
Also tried:
android.net.Proxy. getHost(Context ctx) – which is deprecated – returns the IP
android.net.Proxy. getPortt(Context ctx) – which is deprecated – returns always -1.
Java calls:
System.getProperty("http.proxyHost");
System.getProperty("http.proxyCall");
Also returns null.
Is there a working code which retrieves all these settings or at least partially from devices in all android versions?
I found this project: Android Proxy Library
Which provides backward compatible ways of querying Proxy settings as well as setting them for WebViews on older versions of Android.
// Grab Proxy settings in a backwards compatible manner
ProxyConfiguration proxyConfig = ProxySettings.getCurrentHttpProxyConfiguration( context );
// Set Proxy for WebViews on older versions of Android
ProxyUtils.setWebViewProxy( getActivity().getApplicationContext() );
However, there is something you need to understand about Proxy Settings set on a WiFi AP. Since WiFi specific Proxy Settings were not implemented in Android proper until 3.1, all pre-3.1 devices that expose that functionality are using some sort of custom hack. They don't work in any sort of standard way. So libraries like this won't be able to grab any proxy set from one of those hacks.
There is however a System Wide Proxy in pre-3.1 that this sort of library WILL grab. Of course Android saw fit not to provide any official way to modify this setting. But there are apps on the Play Store that will allow you to do it, this is the one I'm using: Proxy Settings and it works well, setting the System Proxy and allowing you to grab it either via this library, or even simpler methods like querying the JVM proxy settings.
I ended up not using the APL and instead went with a much simpler implementation:
private static final boolean IS_ICS_OR_LATER = Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH;
...
String proxyAddress;
int proxyPort;
if( IS_ICS_OR_LATER )
{
proxyAddress = System.getProperty( "http.proxyHost" );
String portStr = System.getProperty( "http.proxyPort" );
proxyPort = Integer.parseInt( ( portStr != null ? portStr : "-1" ) );
}
else
{
proxyAddress = android.net.Proxy.getHost( context );
proxyPort = android.net.Proxy.getPort( context );
}
This is what I'm using:
public static String[] getUserProxy(Context context)
{
Method method = null;
try
{
method = ConnectivityManager.class.getMethod("getProxy");
}
catch (NoSuchMethodException e)
{
// Normal situation for pre-ICS devices
return null;
}
catch (Exception e)
{
return null;
}
try
{
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
Object pp = method.invoke(connectivityManager);
if (pp == null)
return null;
return getUserProxy(pp);
}
catch (Exception e)
{
return null;
}
}
private static String[] getUserProxy(Object pp) throws Exception
{
String[] userProxy = new String[3];
String className = "android.net.ProxyProperties";
Class<?> c = Class.forName(className);
Method method;
method = c.getMethod("getHost");
userProxy[0] = (String) method.invoke(pp);
method = c.getMethod("getPort");
userProxy[1] = String.valueOf((Integer) method.invoke(pp));
method = c.getMethod("getExclusionList");
userProxy[2] = (String) method.invoke(pp);
if (userProxy[0] != null)
return userProxy;
else
return null;
}
Following is code snippet to retrieve proxy details
public static String getProxyDetails(Context context) {
String proxyAddress = new String();
try {
if (IsPreIcs()) {
proxyAddress = android.net.Proxy.getHost(context);
if (proxyAddress == null || proxyAddress.equals("")) {
return proxyAddress;
}
proxyAddress += ":" + android.net.Proxy.getPort(context);
} else {
proxyAddress = System.getProperty("http.proxyHost");
proxyAddress += ":" + System.getProperty("http.proxyPort");
}
} catch (Exception ex) {
//ignore
}
return proxyAddress;
}
It'll return enmpty if some exception or no proxy detected;
private fun getUserProxy(context: Context): Data {
return try {
val declaredField = WifiConfiguration::class.java.getDeclaredField("mIpConfiguration")
declaredField.isAccessible = true
val data =
(context.applicationContext.getSystemService(Context.WIFI_SERVICE) as? WifiManager)
?.configuredNetworks
?.asSequence()
?.mapNotNull {
try {
declaredField.get(it)
} catch (e: Exception) {
e.printStackTrace()
null
}
}
?.mapNotNull {
try {
(it.javaClass.getDeclaredField("httpProxy").get(it) as? ProxyInfo)
} catch (e: Exception) {
e.printStackTrace()
null
}
}
?.find { !it.host.isNullOrEmpty() }
?.let { Data(it.host ?: "", it.port.toString()) }
?: Data()
declaredField.isAccessible = false
return data
} catch (e: Exception) {
e.printStackTrace()
Data()
}
}
data class Data(
val host: String = "",
val port: String = ""
)
Related
Now with android 10 updated permission and security, we cannot access the user's devices device id and IMEI number but I want some unique id of the device so that we can track the user.
The requirement is we want to have/restrict one login from one phone
Android 10 Restricted developer to Access IMEI number.
You can have a alternate solution by get Software ID. You can use software id as a unique id. Please find below code as i use in Application.
public static String getDeviceId(Context context) {
String deviceId;
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
deviceId = Settings.Secure.getString(
context.getContentResolver(),
Settings.Secure.ANDROID_ID);
} else {
final TelephonyManager mTelephony = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
if (mTelephony.getDeviceId() != null) {
deviceId = mTelephony.getDeviceId();
} else {
deviceId = Settings.Secure.getString(
context.getContentResolver(),
Settings.Secure.ANDROID_ID);
}
}
return deviceId;
}
Android introduced a new id to identify a device uniquely, which is called Advertisement_Id. You can get this Id from the below code implementation in you Application class onCreate method.
/** Retrieve the Android Advertising Id
*
* The device must be KitKat (4.4)+
* This method must be invoked from a background thread.
*
* */
public static synchronized String getAdId (Context context) {
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.KITKAT) {
return null;
}
AdvertisingIdClient.Info idInfo = null;
try {
idInfo = AdvertisingIdClient.getAdvertisingIdInfo(context);
} catch (GooglePlayServicesNotAvailableException e) {
e.printStackTrace();
} catch (GooglePlayServicesRepairableException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
String advertId = null;
try{
advertId = idInfo.getId();
}catch (NullPointerException e){
e.printStackTrace();
}
return advertId;
}
For Kotlin
fun getAdId() {
//Background Task
AsyncTask.execute {
var adInfo: AdvertisingIdClient.Info? = null
try {
adInfo = AdvertisingIdClient.getAdvertisingIdInfo(applicationContext)
if(adInfo!=null){
val id = adInfo!!.getId()
val isLAT = adInfo!!.isLimitAdTrackingEnabled()
PersistData.setStringData(applicationContext, AppConstant.advertId, id)
val advertId = PersistData.getStringData(applicationContext, AppConstant.advertId)
}
} catch (e: IOException) {
// Unrecoverable error connecting to Google Play services (e.g.,
// the old version of the service doesn't support getting AdvertisingId).
} catch (e: GooglePlayServicesAvailabilityException) {
// Encountered a recoverable error connecting to Google Play services.
} catch (e: GooglePlayServicesNotAvailableException) {
// Google Play services is not available entirely.
}
}
}
As Serial number and IMEI number has been deprecated for Android 10 and onwards ,
So we can find the android id for unique identifier with READ_PRIVILEGED_PHONE_STATE.
for More information please follow below link.
https://developer.android.com/training/articles/user-data-ids
getDeviceId() has been deprecated since API level 26.
"READ_PRIVILEGE_PHONE_STATE" is only accessible by The best practices suggest that you should "Avoid using hardware identifiers." for unique identifiers. You can use an instance id from firebase e.g FirebaseInstanceId.getInstance().getId();
public static String getDeviceId(Context context) {
String deviceId;
if (android.os.Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
deviceId = Settings.Secure.getString(
context.getContentResolver(),
Settings.Secure.ANDROID_ID);
} else {
deviceId =FirebaseInstanceId.getInstance().getId();
}
return deviceId;
}
Use FirebaseInstanceId.getInstance().getId(); for Api level above Android 10
This works for me //import android.provider.Settings
val mId = Settings.Secure.getString(this.contentResolver, Settings.Secure.ANDROID_ID)
I am currently having a one special use case that I am quite confused how to solve.
We have been checking for internet connection with ConnectivityService that has those ConnectivityType.Wifi / ConnectivityType.Mobile with a property if it is connected / connecting. That is all good until you run into following case:
You have data enabled on your phone.
Data connection is connected.
However you don't pay for your data bill so you can't make any data transfers.
(make sure your wifi is turned off while trying this)
I thought that I would simply check as following:
private static bool CanReachServer()
{
var uri = new Uri(Platform.ApiServerUrl); // replace with https://www.google.com if you like
try
{
using (HttpClient httpClient = new HttpClient())
{
httpClient.Timeout = TimeSpan.FromMilliseconds(5000);
HttpRequestMessage httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, uri);
var task = httpClient.SendAsync(httpRequestMessage);
task.Wait();
if (task.Result.IsSuccessStatusCode)
return true;
else
return false;
}
}
catch (Exception ex)
{
Util.Log(string.Format("{0} - {1}", ex.Message, ex.StackTrace));
return false;
}
}
But this comes with a result of a successful status 200 - which makes me really confused as I clearly can't access anything data oriented on my phone.
I suggest you to check connection by attempting to open a socket to a known host - if the connection is successful - you can be sure that you have network access, else you can check the Exception and handle it to show error connection.
public bool ActiveInternetConnectivity() {
try {
// connect to google on port 80, the HTTP port
var socket = new Java.Net.Socket("www.google.com", 80);
// the above would have thrown exception if failed, so we are good
socket.Close();
return true;
} catch (Exception ex) {
// check logcat to see why it failed, you could then catch and handle each exception independently ( time out, host unknown, end of stream, etc.. )
System.Diagnostics.Debug.WriteLine(ex);
// the connection has failed, return false
return false;
}
It's just an idea, codes are not fully tested.
Ended up implementing following solution that seem to be working quite reliably. You can also enforce reachability on the method.
public static NetworkState GetNetworkState(this Context context, bool testReachability = false)
{
var result = NetworkState.NoNetwork;
var connMgr = (ConnectivityManager)context.GetSystemService(Context.ConnectivityService);
var activeNetwork = connMgr.ActiveNetworkInfo;
if (activeNetwork == null || !activeNetwork.IsConnectedOrConnecting)
{
connMgr.Dispose();
return NetworkState.NoNetwork;
}
if (activeNetwork.Type == ConnectivityType.Wifi && activeNetwork.IsConnected)
{
if (testReachability)
{
if (CanReachServer())
result = NetworkState.WiFi;
}
else
{
result = NetworkState.WiFi;
}
}
else if (activeNetwork.Type == ConnectivityType.Mobile && activeNetwork.IsConnected)
{
if (testReachability)
{
if (CanReachServer())
result = NetworkState.Mobile;
}
else
{
result = NetworkState.Mobile;
}
}
activeNetwork.Dispose();
connMgr.Dispose();
return result;
}
private static bool CanReachServer()
{
var uri = new Uri(Platform.ApiServerUrl).GetLeftPart(UriPartial.Authority);
var task = Task.Factory.StartNew(() =>
{
try
{
using (URL url = new URL(uri))
{
using (HttpURLConnection urlc = (HttpURLConnection)url.OpenConnection())
{
urlc.SetRequestProperty("User-Agent", "Android Application");
urlc.SetRequestProperty("Connection", "close");
urlc.ConnectTimeout = 6000;
urlc.ReadTimeout = 10000;
urlc.Connect();
bool result = urlc.ResponseCode == HttpStatus.Ok;
urlc.Disconnect();
return result;
}
}
}
catch (Exception ex)
{
Util.Log(string.Format("{0} - {1}", ex.Message, ex.StackTrace));
return false;
}
});
task.Wait();
return task.Result;
}
}
I'm try send DTMF codes in icoming CALL. For this i'n try use Java reflection:
public void initialize(){
ClassLoader classLoader = Dtmf.class.getClassLoader();
final Class<?> classCallManager = classLoader.loadClass("com.android.internal.telephony.CallManager");
Method methodGetInstance = classCallManager.getDeclaredMethod("getInstance");
objectCallManager = methodGetInstance.invoke(null);
methodGetState = classCallManager.getDeclaredMethod(SEND_DTMF, char.class);
}
public boolean sendDtmf(char ch) {
boolean result = false;
if ( methodGetState != null) {
try {
Object res = methodGetState.invoke(objectCallManager,
new Object[]{Character.valueOf(ch)});
if (res instanceof Boolean) {
result = ((Boolean) res).booleanValue();
}
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
}
}
return result;
}
Link for source code of class CallManager : Call Manager source code
But i'm always get "false" in method sendDtmf(). In debug, code is go into next:
Object res = methodGetState.invoke(objectCallManager,
new Object[]{Character.valueOf(ch)});
What wrong?
The method is likely throwing an InvocationTargetException if your application isn't signed with the platform certificate as conventional apps cannot execute these methods (and will not be granted the required platform permissions to do so).
In short: the method is returning false because you're catching (and ignoring) the exception.
There's an open issue (#1428) on the Android issue tracker for sending DTMF tones as it presently isn't possible.
I have used reflection to mount/unmount external storage.it is working below 4.4 Api.
code is below
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.storage.IMountService;
private static final String MOUNT_POINT = "/mnt/ext_usb" or "/mnt/sdcard/" ...
private IMountService mMountService = null;
private synchronized IMountService getMountService() {
if (mMountService == null) {
IBinder service = ServiceManager.getService("mount");
if (service != null) {
mMountService = IMountService.Stub.asInterface(service);
} else {
Log.e(TAG, "Can't get mount service");
}
}
return mMountService;
}
private void mount() {
IMountService mountService = getMountService();
try {
if (mountService != null) {
mountService.mountVolume(MOUNT_POINT);
} else {
//
}
} catch (RemoteException ex) {
// Not much can be done
}
}
private void unmount() {
StorageManager sm = (StorageManager) getSystemService(Context.STORAGE_SERVICE);
String state = sm.getVolumeState(MOUNT_POINT);
if (!Environment.MEDIA_MOUNTED.equals(state) &&
!Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
//
return;
}
IMountService mountService = getMountService();
try {
if (mountService != null) {
mountService.unmountVolume(MOUNT_POINT, true, false);
} else {
Log.e(TAG, "Mount service is null, can't unmount");
}
} catch (RemoteException ex) {
// Not much can be done
}
}
Any workaround to get it working.As it throws Security Exception.android.permission.mount_unmount_filesystems requires.I have decleared this in manifest.I have google about this issue i found that the permission have system|signature protection level.Thanks in advance.
In order to use something with signature | system permissions your package has to be signed by the platform's signing key. Unless you're creating your own custom ROM or have a rooted device, you won't be able to do this.
If your app is a regular 3rd party app (released in the Play store) then you should only use the public APIs and not depend on reflection. Only the public Android APIs are considered stable and exposed. Others are hidden because they are only intended to be used by the internals of the system.
I set an Android:process=":XX" for my particular activity to make it run in a separate process.
However when the new activity/process init, it will call my Application:onCreate() which contains some application level initialization.
I'm thinking of avoiding duplication initialization by checking current process name.
So is there an API available?
Thanks.
Full code is
String currentProcName = "";
int pid = android.os.Process.myPid();
ActivityManager manager = (ActivityManager) this.getSystemService(Context.ACTIVITY_SERVICE);
for (RunningAppProcessInfo processInfo : manager.getRunningAppProcesses())
{
if (processInfo.pid == pid)
{
currentProcName = processInfo.processName;
return;
}
}
Get it from ActivityThread
In API 28+, you can call Application.getProcessName(), which is just a public wrapper around ActivityThread.currentProcessName().
On older platforms, just call ActivityThread.currentProcessName() directly.
Note that prior to API 18, the method was incorrectly called ActivityThread.currentPackageName() but still in fact returned the process name.
Example code
public static String getProcessName() {
if (Build.VERSION.SDK_INT >= 28)
return Application.getProcessName();
// Using the same technique as Application.getProcessName() for older devices
// Using reflection since ActivityThread is an internal API
try {
#SuppressLint("PrivateApi")
Class<?> activityThread = Class.forName("android.app.ActivityThread");
// Before API 18, the method was incorrectly named "currentPackageName", but it still returned the process name
// See https://github.com/aosp-mirror/platform_frameworks_base/commit/b57a50bd16ce25db441da5c1b63d48721bb90687
String methodName = Build.VERSION.SDK_INT >= 18 ? "currentProcessName" : "currentPackageName";
Method getProcessName = activityThread.getDeclaredMethod(methodName);
return (String) getProcessName.invoke(null);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
Compatibility
Tested and working on
Official emulator
16
17
18
19
21
22
23
24
25
26
27
28
Q beta 1
Real devices
Motorola Moto G5 Plus running Android 8.1.0
Samsung Galaxy S5 running Android 6.0.1
Sony Xperia M running stock Android 7.1.1
Sony Xperia M running Sony Android 4.1.2
The ActivityManager solution contains a sneaky bug, particularly if you check your own process name from your Application object. Sometimes, the list returned from getRunningAppProcesses simply doesn't contain your own process, raising a peculiar existential issue.
The way I solve this is
BufferedReader cmdlineReader = null;
try {
cmdlineReader = new BufferedReader(new InputStreamReader(
new FileInputStream(
"/proc/" + android.os.Process.myPid() + "/cmdline"),
"iso-8859-1"));
int c;
StringBuilder processName = new StringBuilder();
while ((c = cmdlineReader.read()) > 0) {
processName.append((char) c);
}
return processName.toString();
} finally {
if (cmdlineReader != null) {
cmdlineReader.close();
}
}
EDIT: Please notice that this solution is much faster than going through the ActivityManager but does not work if the user is running Xposed or similar. In that case you might want to do the ActivityManager solution as a fallback strategy.
This is an update to David Burström's answer. This can be written far more concisely as:
public String get() {
final File cmdline = new File("/proc/" + android.os.Process.myPid() + "/cmdline");
try (BufferedReader reader = new BufferedReader(new FileReader(cmdline))) {
return reader.readLine();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
I have more efficient method, you don't need IPC to ActivityManagerService and poll the Running process, or read the file.You can call this method from your custom Application class;
private String getProcessName(Application app) {
String processName = null;
try {
Field loadedApkField = app.getClass().getField("mLoadedApk");
loadedApkField.setAccessible(true);
Object loadedApk = loadedApkField.get(app);
Field activityThreadField = loadedApk.getClass().getDeclaredField("mActivityThread");
activityThreadField.setAccessible(true);
Object activityThread = activityThreadField.get(loadedApk);
Method getProcessName = activityThread.getClass().getDeclaredMethod("getProcessName", null);
processName = (String) getProcessName.invoke(activityThread, null);
} catch (Exception e) {
e.printStackTrace();
}
return processName;
}
ActivityManagerService is already send the process infor to ActivityThread when process is start.(ActivityThread.main-->attach()-->IActivityManager.attachApplication--IPC-->ActivityManagerService-->ApplicationThread.bindApplication)
ApplicationThread:
public final void bindApplication(String processName,***) {
//***
AppBindData data = new AppBindData();
data.processName = processName;
//**
}
When we called getProcessName, it will finally deliver to AppBindData object.
So we can easily and efficient get current process name;
To wrap up different approaches of getting process name using Kotlin:
Based on the https://stackoverflow.com/a/21389402/3256989 (/proc/pid/cmdline):
fun getProcessName(): String? =
try {
FileInputStream("/proc/${Process.myPid()}/cmdline")
.buffered()
.readBytes()
.filter { it > 0 }
.toByteArray()
.inputStream()
.reader(Charsets.ISO_8859_1)
.use { it.readText() }
} catch (e: Throwable) {
null
}
Based on https://stackoverflow.com/a/55549556/3256989 (from SDK v.28 (Android P)):
fun getProcessName(): String? =
if (VERSION.SDK_INT >= VERSION_CODES.P) Application.getProcessName() else null
Based on https://stackoverflow.com/a/45960344/3256989 (reflection):
fun getProcessName(): String? =
try {
val loadedApkField = application.javaClass.getField("mLoadedApk")
loadedApkField.isAccessible = true
val loadedApk = loadedApkField.get(application)
val activityThreadField = loadedApk.javaClass.getDeclaredField("mActivityThread")
activityThreadField.isAccessible = true
val activityThread = activityThreadField.get(loadedApk)
val getProcessName = activityThread.javaClass.getDeclaredMethod("getProcessName")
getProcessName.invoke(activityThread) as String
} catch (e: Throwable) {
null
}
Based on https://stackoverflow.com/a/19632382/3256989 (ActivityManager):
fun getProcessName(): String? {
val pid = Process.myPid()
val manager = appContext.getSystemService(Context.ACTIVITY_SERVICE) as? ActivityManager
return manager?.runningAppProcesses?.filterNotNull()?.firstOrNull { it.pid == pid }?.processName
}
First, get the current process pid. Second, list all processes of running. Finally, if it has equal pid, it's ok, or it's false.
public static String getProcessName(Context context) {
int pid = android.os.Process.myPid();
ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> infos = manager.getRunningAppProcesses();
if (infos != null) {
for (ActivityManager.RunningAppProcessInfo processInfo : infos) {
if (processInfo.pid == pid) {
return processInfo.processName;
}
}
}
return null;
}
Since Android Pie (SDK v28), there is actually an official method for this in the Application class:
public static String getProcessName ()
See the docs
If I've understood your question correctly, you should be able to use ActivityManager, as per this thread.
There is a method in ActivityThread class, You may use reflection to get the current processName. You don't need any loop or tricks. The performance is best compares to other solution. The limitation is you can only get your own process name. It's not a big deal since it covers most usage cases.
val activityThreadClass = XposedHelpers.findClass("android.app.ActivityThread", param.classLoader)
val activityThread = XposedHelpers.callStaticMethod(activityThreadClass, "currentActivityThread")
val processName = XposedHelpers.callStaticMethod(activityThreadClass, "currentProcessName")
The main process's father process should be zygote, this should be the accurate solution
first judge the process's name from /proc/pid/cmdline which should equal to package name
judge the process's father whether Zygote(why do this? because some APP have different processes with same name)