Friday, November 27, 2009

Calling private methods in Android

First and foremost, I won't be held responsible for the content of the article if applied to your apps, and if it results in any kinds of misfunctions and such. Use it at your own risk and use it when there's are no other way that is available in android.

In java, there is a set of API called Reflection API, see this for more detailed look and this for examples. What Reflection does is that it will, from its name, reflect the class for you, reflecting public, private, protected, static and even native variables, function/methods, classes and more. By getting their reflection you could execute private functions or get private class. In this article however, will focus on calling private methods on a public class. We would use SmsManager and test it on Android 1.6 throughout this article.

Update:
1- There is a bug on the emulator, i tested this on G1, sendRawPdu is missing on the reflection


try {
  // the following would just be (but using reflections)
  // sm.sendTextMessage("", null, "Test", null, null);

  // initialize variables
  SmsManager sm = SmsManager.getDefault();
  Class c = sm.getClass();

  // debug, print all methods in this class , there are 2 private methods in this class
  Method[] ms = c.getDeclaredMethods();
  for (int i = 0; i < ms.length; i++)     Log.d("ListMethos",ms[i].toString());   // get private method 1   Method m1 = SmsManager.class.getDeclaredMethod("createMessageListFromRawRecords", List.class);   Log.d("success","success getting sendRawPdu");   // get private method 2   byte[] bb = new byte[1];   Method m2 = SmsManager.class.getDeclaredMethod("sendRawPdu",bb.getClass(),bb.getClass(), PendingIntent.class,PendingIntent.class);   Log.d("success","success getting sendRawPdu");   // send message   m2.setAccessible(true);   SmsMessage.SubmitPdu pdus = SmsMessage.getSubmitPdu( null,"", "Test", false);
  m2.invoke(sm, pdus.encodedScAddress, pdus.encodedMessage, null, null );

  Log.d("success","success sedding message");
} catch (SecurityException 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 (IllegalAccessException e) {
  // TODO Auto-generated catch block
  e.printStackTrace();
} catch (InvocationTargetException e) {
  // TODO Auto-generated catch block
  e.printStackTrace();
}



Explanation
Get the private method from the SmsManager class having one argument of List
Method m1 = SmsManager.class.getDeclaredMethod("createMessageListFromRawRecords", List.class);
-- From our trace: D/ListMethos( 2900): private java.util.ArrayList android.telephony.SmsManager.createMessageListFromRawRecords(java.util.List)

Get another method from SmsManager that has 4 argument
Method m2 = SmsManager.class.getDeclaredMethod("sendRawPdu",bb.getClass(),bb.getClass(), PendingIntent.class,PendingIntent.class);
-- From our trace: D/ListMethos( 2900): private void android.telephony.SmsManager.sendRawPdu(byte[],byte[],android.app.PendingIntent,android.app.PendingIntent)

Make the private function to be public
m2.setAccessible(true);

Call the method m2(sendRawPdu) on SmsManager object with the following parameters
m2.invoke(sm, pdus.encodedScAddress, pdus.encodedMessage, null, null );

Basically thats it :) Hope this helps and remember limit the use of this, its not recommended by all means :)

Tuesday, November 24, 2009

Releasing SpeakUp Android App Source

After not making it through ADC2, me and my friends decided to release the source code of SpeakUp, unlike previous projects like Monmonja Battery and Talking Caller, we are releasing it under GPLv3. We believe this would be better to keep this project and other projects that will use the source base to be in and stay in the open source world. We are releasing the official ADC version of the App, the market version of the app would remain closed source until we decided to open it up too (most probably, and currently they are almost the same). Anyway hope this sources would help others in making android apps.

On the new source, there are few updates and few fixes and uses the default TextToSpeech in android 1.6.

Head over Google code for the source.
SpeakUp in Google Code

Thursday, November 19, 2009

Select a RadioButton from Multiple RadioGroup in Android

I bounds into Radiogroup layout question while trying out something in android. The problem is that you want a RadioButton but you don't want it to just be either horizontally placed or vertically placed which is the default way RadioGroup does. Say you want 2 rows of 4 RadioButton, by default you cant do this with one RadioGroup, so the solution is to make 2 RadioGroup but the problem now is that you need to handle both RadioGroup in turn that when one RadioButton is selected on one RadioGroup the other RadioGroup/s will deselect itself. To do this here is the code on how i did it (it has 3 RadioGroups), it might not be the best solution :)

private Boolean changeGroup = false;
public void onCheckedChanged(RadioGroup group, int checkedId){
  if (group != null && checkedId > -1 && changeGroup == false){
    if(group == frequencyGroup1){
      changeGroup = true;
      frequencyGroup2.clearCheck();
      frequencyGroup3.clearCheck();
      changeGroup = false;
    }else if(group == frequencyGroup2){
      changeGroup = true;
      frequencyGroup1.clearCheck();
      frequencyGroup3.clearCheck();
      changeGroup = false;
    }else if(group == frequencyGroup3){
      changeGroup = true;
      frequencyGroup1.clearCheck();
      frequencyGroup2.clearCheck();
      changeGroup = false;
    }
  }
}


Explanation
Create a flag stating that we mark as whether the function could be execute or not (see below)
private Boolean changeGroup = false;

On the default change function of RadioGroup, create a conditional statement that would execute the change function of all RadioGroup only when our flag state that it can execute the next code block. By default this function will execute when you select a RadioButton on a Group and/or when you call clearCheck() of each RadioGroup, and you may not want to do that especially when we call clearCheck.
if (group != null && checkedId > -1 && changeGroup == false){

The following code will just set the flag to true when users select a RadioButton on any group, thus when other RadioGroup call clearCheck() the code block in the function will not be called.
.....


Hope i could explain it more clearly but its kinda hard :)

Update History
   Jan 17, 2012 - Visual Update

Sunday, November 8, 2009

Want to test your app in x86 android?

After weeks of being busy, finally had a time to play with android :) So i tried the live cd of android x86. Head over http://code.google.com/p/live-android/downloads/list and download the latest version.

Im using parallel on mac and i could get the internet and other stuff to work, the market is not the default market you have on your android phone right now but its an okay market. Its quite fast since i allocated 1Gb of ram to it. lol

Search Amazon.com for android phone

By this I its faster to debug your application using this than the emulator. If you want do to so, here is a brief concept of how it could work.
* Make sure you have a webserver (XAMPP should be fine)
* If its newly installed then change the DocumentRoot of Apache (not really recommended) to the location of your working environment (your workspace folder), the configuration of apache is at under xamppfiles/etc/httpd.conf of your XAMPP folder on
* If you dont want to change the DocumentRoot of your Apache or if the previous step didnt work, then either make a symbolic link of the folder, mount the folder, create a VirtualHost on httpd.conf. I'm not really sure of this one. Will any apache expert shared a light on this one. Thanks.
* Start and restart your apache (use the XAMPP control applet/panel)
* On your virtual machine, head over the browser to download your app. By default when you compile in eclipse an apk is generated under the bin folder. For example http://192.168.1.100/workspace/monBattery/bin/monBattery.apk and it should install.

I'll update the last part of the post when the concept becomes a reality. :)