Check if method exists - android

I want to check if the method Camera.Parameters.getHorizontalViewAngle() exists on the device (it's only available from API 8 and my min SDK API is 7). I tried to use "reflection", as explained here, but it catches an error saying the number of arguments is wrong:
java.lang.IllegalArgumentException: wrong number of arguments
Anybody could help?
Camera camera;
camera = Camera.open();
Parameters params = camera.getParameters();
Method m = Camera.Parameters.class.getMethod("getHorizontalViewAngle", new Class[] {} );
float hVA = 0;
try {
m.invoke(params, hVA);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

m.invoke(params, hVA);
should be
m.invoke(params, null);
Camera.Parameters.getHorizontalViewAngle() doesn't take any arguments and the above line has the argument hVA. If you're looking for the return variable do hVA = m.invoke(params, null);

Personally, I recommend conditional class loading, where you isolate the new-API code in a class that you only touch on a compatible device. I only use reflection for really lightweight stuff (e.g., finding the right CONTENT_URI value to use for Contacts or ContactsContract).
For example, this sample project uses two implementations of an abstract class to handle finding a Camera object -- on a Gingerbread device, it tries to use a front-facing camera.
Or, this sample project shows using the action bar on Honeycomb, including putting a custom View in it, while still maintaining backwards compatibility to older versions of Android.

I know this is a hack, but why can't you put the first call to the method in a try/catch of it's own, and nest the rest of your try/catch code in there. If the outer catch executes, the method doesn't exist.

Related

Android - where can I see the request url that is generated when setDataSource(..) is called?

I am trying to add headers to my setDataSource() method. Is there any way I could see the request itself that is sent ? I need to do this because I'd like to confirm if the url generated by setDataSource method is correctly formed. I don't however see any apis in the MediaPlayer class that can help me do this. Any direction or a solution would be most appreciated.
For non-file media source, the framework handle it by MediaHTTPConnection which is a hide API. You can change its field VERBOSE to true to see the printed log.
Since it's not exported, we can't use it directly. The following code might helpful, but I am not sure if it works. Run it before setDataSource().
try {
Class mediaServiceClass = Class.forName("android.media.MediaHTTPConnection");
Field field = mediaServiceClass.getDeclaredField("VERBOSE");
field.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.setBoolean(null, true);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
You can refer here to see the detail implementation of MediaHTTPConnection.

Is reflection useful for Android?

I learnt a bit about reflection after reading about it in some tpics here. From what I understands, it is used to check the avaibility of a certain class/method/field at runtime. But is it really useful in Android ? Android provide us with the api version at runtime and we can know if a particular class/method or field is available by reading the Android doc (or with error message with Android Studio).
I understand how it can be useful with Java in general, but is there any meaning to use it in Android?
Reflection (in every languages) is very powerful.
In Android most of time reflection is not needed, because you can find Security Exceptions, problems. It depends on what You do.
If you use undocumented classes, libs, you can use it, and it's very useful.
Sometimes, to do particular things, like turn on/off 3g on old device, change device language, you need rooted device to use reflection.
Finally, depends always on what You do.
Sometimes it works , and some times it does't work .
E.T work example :
You can reflect the method to hang off a phone call (there are a lot example codes on Internet so I won't copy the code.).
Doesn't work example:
If you want to switch data connect status , use reflection works on 4.4 but will not work on 5.0 because it's a binder connection, the BN will check Permission the app granted , but this permission only granted to system app . So if your app is a third part app,on 5.0 you can't use reflection to switch data connect status.
Hope that helps
This is a very general question, it really depends on what you're trying to do. Sometimes you have to use reflection, if the APIs are hidden, all depends on your use case, generally you should avoid reflection as it complicates your code more than its needs to be and its potentially unsafe for further versions of android.
In my opinion it's a good to way to do particular things.
For example you can use the methods of PowerProfile class to do a simple power model for your phone.
By the method getAveragePower(POWER_WIFI_SCAN) you can take the average current in mA consumed by the subsystem (in this case: wi-fi during scan).
So to use PowerProfile's methods for get your battery capacity you you could use java reflection in this way:
private Object mPowerProfile_;
private static final String POWER_PROFILE_CLASS = "com.android.internal.os.PowerProfile";
private Double batteryCapacity = Double.valueOf(1);
public Double getBatteryCapacity(Context ctx) {
try {
mPowerProfile_ = Class.forName(POWER_PROFILE_CLASS).getConstructor(Context.class).newInstance(this);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try {
batteryCapacity = (Double) Class.forName(POWER_PROFILE_CLASS).getMethod("getAveragePower", String.class).invoke(mPowerProfile_, "battery.capacity");
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}

disable data connection in dual sim android

I want to disable data connection and I am using this code.
ConnectivityManager dataManager;
dataManager = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
try {
dataMtd = ConnectivityManager.class.getDeclaredMethod("setMobileDataEnabled", boolean.class);
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
dataMtd.setAccessible(true);
try {
dataMtd.invoke(dataManager, false);
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this will not work in dual sim. so can someone help me.
how can I disable data connection in dual sim android phone?
and how can i check if phone is dual sim or not
Some things to mention here:
before Android 5.1 there was no official API for dual sim functionality. Thus there seems to be no universal solution for older devices. Since 5.1 an API is available.
your code will no longer work on Android 5+, as pointed out in this question
however, this answer provides a solution to both bullets above: the method setMobileNetworkfromLollipop checks whether target is 5 or 5.1+, and in case of 5.1+ it loops through all subscription id's (=sim cards) to switch data services. You could combine it with your code to target previous versions as well. The downside: it requires root access, and dual-sim functionality is limited to 5.1+.

setPin() shows error in eclipse that "setPin() is undefined for BluetoothDevice"

I don't find many BluetoothDevice methodes such as , setPasskey(), setPin(), setPairingConfirmation(), setRemoteOutOfBandData().
I searched on Android site as well but I don't find it. When I use these methods in my program in eclipse it shows me an error: its undefined for the type BluetoothDevice.
Are these obsolete now? If yes then what are the new methods of same type.
It is assumed that paring process is performed only by applications delivered with a platform!
This means that this application have access to hidden API. For example you can find hidden API for Bluetooth here.
It is strongly recommended to not use hidden API since it can change without warning in next Android release.
If you are still planning to use this API safest way is to use reflection:
try {
Class<? extends BluetoothDevice> c = device.getClass(); // BluetoothDevice.class
Method createBond = c.getMethod("createBond");
Object result = createBond.invoke(device);
Boolean castedResult = (Boolean)result;
Log.d(TAG, "Result: " + castedResult.toString());
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
There is also alternative way to easy use hidden API, but I didn't try it.

Android- Using DexClassLoader to load apk file

I've hit a bit of a wall. Any help would be appreciated. I have an app that I want to use DexClassLoader to load another apk file.
Here is my code:
DexClassLoader dLoader = new DexClassLoader("/sdcard/download/test.apk","/sdcard/download",null,ClassLoader.getSystemClassLoader().getParent());
Class calledClass = dLoader.loadClass("com.test.classname");
Intent it=new Intent(this, calledClass);
it.setClassName("com.test", "com.test.classname");
startActivity(it);
Now I had already installed test.apk so when I ran the above code it
worked fine and launched the application. However I want to be able to
run this without test.apk being installed already (as that would
defeat the entire point of the application) . So I uninstalled it and
when I ran the my app again I get this error:
android.content.ActivityNotFoundException: Unable to find explicit
activity class {com.test/com.test.classname}; have you declared this
activity in your AndroidManifest.xml.
So I'm a bit stumped here. This activity is declared in the Manifest
of the apk I am trying to run. I can't declare it in my applications
Manifest. Any ideas?
Thanks,
Craig
Try using Android's PathClassLoader:
String packagePath = "com.mypackage";
String classPath = "com.mypackage.ExternalClass";
String apkName = null;
try {
apkName = getPackageManager().getApplicationInfo(packagePath,0).sourceDir;
} catch (PackageManager.NameNotFoundException e) {
// catch this
}
// add path to apk that contains classes you wish to load
String extraApkPath = apkName + ":/path/to/extraLib.apk"
PathClassLoader pathClassLoader = new dalvik.system.PathClassLoader(
apkName,
ClassLoader.getSystemClassLoader());
try {
Class<?> handler = Class.forName(classPath, true, pathClassLoader);
} catch (ClassNotFoundException e) {
// catch this
}
Although the question is old, I will answer because I struggled a bit to find a clear answer for your same question for myself. First, I would like to highlight that a clear requirement in your question is to load a class from an .apk that is not already installed on the device. Therefore, calling the package manager using getPackageManager() and providing it with the package path will clearly lead to NameNotFoundException because the .apk that has the package is not installed on the device.
So, the way to go about loading classes from an .apk file that is not installed on the device (i.e. you only have the .apk stored in a directory on your SDCARD) is by using DexClassLoader as follows:
1- Make sure you have the .apk file in a directory on your SDCARD. I've mine Offloadme.apk in the Download folder on my SDCARD.
2- Add read permission in your AndroidManifest.xml to allow your app to read from the manifest.
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
3- Use the following definitions to define the path of the .apk, the class name inside the apk, and method name in that class that you would like to invoke:
final String apkFile =Environment.getExternalStorageDirectory().getAbsolutePath()+"/Download/Offloadme.apk";
String className = "com.khaledalanezi.offloadme.SimpleCalculator";
String methodToInvoke = "add";
4- Use the DexClassLoader to load the .apk and call the add method in the SimpleCalculator class using reflection as follows:
final File optimizedDexOutputPath = getDir("outdex", 0);
DexClassLoader dLoader = new DexClassLoader(apkFile,optimizedDexOutputPath.getAbsolutePath(),
null,ClassLoader.getSystemClassLoader().getParent());
try {
Class<?> loadedClass = dLoader.loadClass(className);
Object obj = (Object)loadedClass.newInstance();
int x =5;
int y=6;
Method m = loadedClass.getMethod(methodToInvoke, int.class, int.class);
int z = (Integer) m.invoke(obj, y, x);
System.out.println("The sum of "+x+" and "+"y="+z);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Note that in my simple example, I added two numbers using the add method available in the SimpleCalculator class loaded from the Offloadme.apk file stored on my SDCARD and I was able to print the correct answer which is 11.
You can't do that. Even if you're able to access classes from external file, Android still does not know them. And you don't run activities directly, but by requesting Android to run them, so they have to be registered/installed into system.

Categories

Resources