Refactor method which uses reflection from Java to Kotlin - java

I am trying to convert Java method which checks the SignalStrength level for Android API's which is like this:
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;
}
}
When converted to Kotlin I am getting this (I aim to make Kotlin Extension):
fun SignalStrength.getSignalLevel(): Int {
return try {
val m = SignalStrength::class.java.getDeclaredMethod("getLevel", *null as Array<Class<*>>?)
m.isAccessible = true
m.invoke(this, *null as Array<Any>?) as Int
} catch (e: Exception) {
0
}
}
The issue is for:
*null as Array<Class<*>>?
The spread operator (*foo) may not be applied to an argument of nullable type

Related

How can I solve LI_LAZY_INIT_UPDATE_STATIC?

I'm trying to initialize a MethodHandle for a non-public method in an upstream library.
private static Method OF_METHOD;
static Method ofMethod() {
if (OF_METHOD == null) {
try {
OF_METHOD = RequestObject.class.getDeclaredMethod(
"of", Class.class, String.class, String.class,
Object.class, Object.class);
if (!OF_METHOD.isAccessible()) {
OF_METHOD.setAccessible(true);
}
} catch (final NoSuchMethodException nsme) {
throw new RuntimeException(nsme);
}
}
return OF_METHOD;
}
private static MethodHandle OF_HANDLE;
static MethodHandle ofHandle() {
if (OF_HANDLE == null) {
try {
OF_HANDLE = MethodHandles.lookup().unreflect(ofMethod());
} catch (final ReflectiveOperationException roe) {
throw new RuntimeException(roe);
}
}
return OF_HANDLE;
}
And my SpotBugs Bug Detecter Report says the ofMethod() has a LI_LAZY_INIT_UPDATE_STATIC problem.
I understand what it's saying. I see those two steps(assigning and setting accessible) are problematic in multi-threaded environment.
How can I solve the problem? Should I apply Double-checked locking?
Or should I put ofMethod() logic into ofHandle()?
I'm answering for my own question.
The idea of holding a lazy object reference is a bad idea.
Even with the Double-checked locking,
private static volatile Method OF_METHOD;
static Method ofMethod() {
Method ofMethod = OF_METHOD;
if (ofMethod == null) {
synchronized (JacksonRequest.class) {
ofMethod = OF_METHOD;
if (ofMethod == null) {
try {
ofMethod = ...;
} catch (final NoSuchMethodException nsme) {
throw new RuntimeException(nsme);
}
if (!ofMethod.isAccessible()) {
ofMethod.setAccessible(true);
}
OF_METHOD = ofMethod;
}
}
}
return ofMethod;
}
Anyone can change the accessible state.
I ended up with following code which doesn't depend on any external variables.
static Method ofMethod() {
try {
final Method ofMethod = ...;
if (!ofMethod.isAccessible()) {
ofMethod.setAccessible(true);
}
return ofMethod;
} catch (final NoSuchMethodException nsme) {
throw new RuntimeException(nsme);
}
}

create different InverseBindingAdapter for Short and Integer values on android:text of EditText

I create these methods for custom data binding
#BindingAdapter("android:text")
public static void setShortText(TextView view, short value) {
view.setText(String.valueOf(value));
}
#InverseBindingAdapter(attribute = "android:text")
public static Short getShortText(TextView view) {
try {
return Short.parseShort(view.getText().toString());
} catch (NumberFormatException e) {
return null;
}
}
#BindingAdapter("android:text")
public static void setIntText(TextView view, int value) {
view.setText(String.valueOf(value));
}
#InverseBindingAdapter(attribute = "android:text")
public static Integer getIntText(TextView view) {
try {
return Integer.parseInt(view.getText().toString());
} catch (NumberFormatException e) {
return null;
}
}
and bind my Short and Integer variables to views. when I build my project, the auto generated java uses the first three methods and it's have no usage from the fourth one (getIntText), and the problem is here. it use getShortText for Integer fields and cause compile time casting error.
I'm surprised, data binder properly detect it should use setIntText for set Integer values to views but it can't recognize that for inverseBinding.
how can I fix the problem?
please note that I prefer not use from below technique because I want to have control on binding when data in null
android:text="#={`` + obj.field}
I find a solution, but really not satisfy myself.
I change getIntText return value from Integer to int and problem is solved.
if someone find other better solution please let me know.
#InverseBindingAdapter(attribute = "android:text")
public static int getIntText(TextView view) {
try {
return Integer.parseInt(view.getText().toString());
} catch (NumberFormatException e) {
return -1;
}
}
For this solution to work correctly, it is necessary to make it possible to receive a null value, and check if the new value of TextView is different from the previous value.
If I contract, the Binding methods will be executed forever.
Here is my solution:
#BindingAdapter("android:text")
fun setBindShortText(view: TextView, value: Short?) {
value?.let {
if (!it.toString().contentEquals(view.text))
view.text = it.toString()
}
}
#InverseBindingAdapter(attribute = "android:text")
fun getBindShortText(view: TextView): Short? {
return try {
view.text.toString().toShort()
} catch (e: java.lang.NumberFormatException) {
null
}
}
#BindingAdapter("android:text")
fun setBindIntText(view: TextView, value: Int?) {
value?.let {
if (!it.toString().contentEquals(view.text))
view.text = it.toString()
}
}
#InverseBindingAdapter(attribute = "android:text")
fun getBindIntText(view: TextView): Int? {
return try {
view.text.toString().toInt()
} catch (e: NumberFormatException) {
null
}
}

Count traffic separately for each SIM on 2SIM MTK-based phone

Any app I could find on GPlay counts traffic for both SIM while in Settings-Data Usage traffic is counted for each SIM. I used jd-gui to see how it's done and have found that classes from private API were used.
import android.net.INetworkStatsService;
import android.net.INetworkStatsService.Stub;
import android.net.INetworkStatsSession;
import android.net.NetworkPolicy;
import android.net.NetworkPolicyManager;
import android.net.NetworkStats;
import android.net.NetworkStats.Entry;
import android.net.NetworkStatsHistory;
import android.net.NetworkStatsHistory.Entry;
import android.net.NetworkTemplate;
Can I use reflection to use them?
Update.
I've tried to use Reflection. Executing this code give me an exception "java.lang.InstantiationException: can't instantiate class android.net.INetworkStatsService"
Class<Object> MyINetworkStatsService = null;
try {
MyINetworkStatsService = (Class<Object>) Class.forName("android.net.INetworkStatsService");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Object mStatsService = null;
try {
mStatsService = MyINetworkStatsService != null ? MyINetworkStatsService.newInstance() : null;
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
Upd. Because both StatsService and StatsSession are interfaces, I can't instantiate them and should use Proxy. Can anyone help with that?
Upd. I've made an effort
String id = getActiveSubscriberId(mContext);
try {
Object tmpl = null;
long stats = 0;
Class<?> a = Class.forName("android.net.NetworkTemplate");
Class<?> b = Class.forName("android.net.INetworkStatsService");
Method getState = b.getMethod("getNetworkTotalBytes", a, long.class, long.class);
Method[] am = a.getDeclaredMethods();
Method getTemplate = null;
for (Method m : am) {
if (m.getName().equalsIgnoreCase("buildTemplateMobileAll")) {
getTemplate = m;
break;
}
}
if (getTemplate != null) {
getTemplate.setAccessible(true);
tmpl = getTemplate.invoke(a.getClass(), id);
}
Object object = Proxy.newProxyInstance(b.getClass().getClassLoader(), b.getInterfaces(), new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getName().equals("getNetworkTotalBytes")) {
return method.invoke(args[0], args[1], args[2], args[3]);
}
throw new RuntimeException("no method found");
}
});
Object[] args = {b.getClass(), tmpl, Long.MIN_VALUE, Long.MAX_VALUE};
stats = (long) ((b.getClass()) object).getState(args);
} catch (ClassNotFoundException e0) {
} catch (NoSuchMethodException e0) {
} catch (IllegalAccessException e0) {
} catch (InvocationTargetException e0) {
}
But it says that there is an error "Method call expected" in
stats = (long) ((b.getClass()) object).getState(args);
If I change this string like this
stats = (long) ((b) object).getState(args);
I get another error - "Unknown class: 'b'"

Is there any way to don't use 'instance of' with objects that I can't extend?

I've a custom exception with few attributes that inherits from Exception class.
Depending on instance of Exception I would like to return a code.
Code:
public int manageException(Exception exception) {
int code = 0;
if (exception instanceof MyCustomException) {
code = ((MyCustomException) exception).getCode();
} else if (exception instanceof NestedRuntimeException) {
code = 444;
} else if (exception instanceof HibernateException) {
code = 555;
} else {
code = 666;
}
return code;
}
If
You need to handle these exceptions in multiple locations, and
You don't want multiple catch blocks (one for each exception type) in each location
...then instanceof is about as clean as you're likely to get in Java 7.
Having said that, though, you could do this:
public void manageException(Runnable r) {
try {
r.run();
}
catch (NestedRuntimeException nre) {
throw new MyCustomException(444, nre);
}
catch (HibernateException he) {
throw new MyCustomException(555, he);
}
catch (Exception e) {
throw new MyCustomException(666, e);
}
}
...and then everywhere you need it:
try {
this.manageException(new Runnable() {
#Override
public void run() {
// Do something
}
});
}
catch (MyCustomException mce) {
int code = mce.getCode();
}
...but it's not buying you much and it's really ugly. :-)
In Java 8, it's a lot cleaner. manageException is the same, but the calls are just:
try {
this.manageException(() => {
// Do something here
});
}
catch (MyCustomException mce) {
int code = mce.getCode();
}
For me, the Java 8 version nearly starts winning over instanceof. The Java 7 version, not so much.
(Why Runnable in the above? Because the JDK authors decided not to define a new standard functional interface that accepts no arguments and has no return value; more in this question. They generalized the concept of Runnable instead. If the semantics bother you (they would me), you can define your own.)
You can use overloading like this:
public int manageException(MyCustomException e) {
return e.getCode();
}
public int manageException(NestedRuntimeException e) {
return 444;
}
public int manageException(HibernateExceptionexception e) {
return 555;
}
public int manageException(Exception e) {
return 666;
}
Edit after comment from #T.J. Crowder:
Keep in mind that you will still need multiple catch blocks in order to call the correct method. The overload is based on the compile-time type of the exception. Simply doing catch (Exception e) { int code = this.manageException(ex); } will always return 666.
If you want to map the type of exception to different error codes, you could use a map:
Map<Class<? extends Exception>, Integer> map = new HashMap<> ();
map.put (Exception.class, 5);
map.put (NullPointerException.class, 42);
try {
throw null; //throws NPE
} catch (Exception e) {
System.out.println (map.get (e.getClass ())); //output is 42
}
I think this would be easy expendable, as you could read the mapping from a config file instead of hard coding it, so you could add other exception and error codes without making changes to your code.
You have to test the return value of map.get() for null, as it could be an Exception you didn't specify before so there is no Integer mapped to it.
Attention: As mentioned in the first comment, this would only work if you want to have an exact mapping of Classes to error codes. If Subclasses of an exception should have the same error code as their super class, this solution won't work without modification.

Programmatically retrieve permissions from manifest.xml in android

I have to programmatically retrieve permissions from the manifest.xml of an android application and I don't know how to do it.
I read the post here but I am not entirely satisfied by the answers.
I guess there should be a class in the android API which would allow to retrieve information from the manifest.
Thank you.
You can get an application's requested permissions (they may not be granted) using PackageManager:
PackageInfo info = getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_PERMISSIONS);
String[] permissions = info.requestedPermissions;//This array contains the requested permissions.
I have used this in a utility method to check if the expected permission is declared:
//for example, permission can be "android.permission.WRITE_EXTERNAL_STORAGE"
public boolean hasPermission(String permission)
{
try {
PackageInfo info = getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_PERMISSIONS);
if (info.requestedPermissions != null) {
for (String p : info.requestedPermissions) {
if (p.equals(permission)) {
return true;
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
Here's a useful utility method that does just that (in both Java & Kotlin).
Java
public static String[] retrievePermissions(Context context) {
final var pkgName = context.getPackageName();
try {
return context
.getPackageManager()
.getPackageInfo(pkgName, PackageManager.GET_PERMISSIONS)
.requestedPermissions;
} catch (PackageManager.NameNotFoundException e) {
return new String[0];
// Better to throw a custom exception since this should never happen unless the API has changed somehow.
}
}
Kotlin
fun retrievePermissions(context: Context): Array<String> {
val pkgName = context.getPackageName()
try {
return context
.packageManager
.getPackageInfo(pkgName, PackageManager.GET_PERMISSIONS)
.requestedPermissions
} catch (e: PackageManager.NameNotFoundException) {
return emptyArray<String>()
// Better to throw a custom exception since this should never happen unless the API has changed somehow.
}
}
You can get a working class from this gist.
Use this:
public static String getListOfPermissions(final Context context)
{
String _permissions = "";
try
{
final AssetManager _am = context.createPackageContext(context.getPackageName(), 0).getAssets();
final XmlResourceParser _xmlParser = _am.openXmlResourceParser(0, "AndroidManifest.xml");
int _eventType = _xmlParser.getEventType();
while (_eventType != XmlPullParser.END_DOCUMENT)
{
if ((_eventType == XmlPullParser.START_TAG) && "uses-permission".equals(_xmlParser.getName()))
{
for (byte i = 0; i < _xmlParser.getAttributeCount(); i ++)
{
if (_xmlParser.getAttributeName(i).equals("name"))
{
_permissions += _xmlParser.getAttributeValue(i) + "\n";
}
}
}
_eventType = _xmlParser.nextToken();
}
_xmlParser.close(); // Pervents memory leak.
}
catch (final XmlPullParserException exception)
{
exception.printStackTrace();
}
catch (final PackageManager.NameNotFoundException exception)
{
exception.printStackTrace();
}
catch (final IOException exception)
{
exception.printStackTrace();
}
return _permissions;
}
// Test: Log.wtf("test", getListOfPermissions(getApplicationContext()));
If anyone is looking for a short Kotlin Version
fun Manifest.getDeclaredPermissions(context: Context): Array<String> {
return context.packageManager.getPackageInfo(context.packageName, PackageManager.GET_PERMISSIONS).requestedPermissions
}
I have a simple C# code, "using System.Xml"
private void ShowPermissions()
{
XmlDocument doc = new XmlDocument();
doc.Load("c:\\manifest.xml");
XmlNodeList nodeList = doc.GetElementsByTagName("uses-permission");
foreach(XmlNode node in nodeList)
{
XmlAttributeCollection Attr = node.Attributes;
string Permission=Attr["android:permission"].Value;
MessageBox.Show(Permission);
}
}

Categories

Resources