Monday 31 March 2014

Hidden Android APIs: Settings

In the previous tutorial we talked about the hidden Android APIs, how to discover them and how to use them in our apps. To be more precise, we saw that the easiest way to use the hidden APIs is to copy hidden constants from the Android source code into our Activities (this way we can, for example, set up a BroadcastReceiver to intercept incoming SMS messages).



The same method can be used to start Activities to change specific system settings directly from our app. As far as system settings are concerned, there are some settings that are available in the official and public APIs. An example is the constant Settings.ACTION_AIRPLANE_MODE_SETTINGS, through which we can show settings to allow entering/exiting airplane mode. But there are a lot of other settings which are available only in the hidden APIs. To find them, look for the Settings class with AndroidXRef, as follows:


To find the hidden settings you just have to look for the "@hide" tag. You will find all the constants you can use to create Intents to launch specific parts of the settings UI.
For example, if you want to launch an Activity to check system updates, you can use the hidden constant Settings.ACTION_SYSTEM_UPDATE_SETTINGS:



As you can see from the Android source code, this constant is marked with the "@hide" tag, so it is not visible in the official API.
You can use this constant in the following way:

Intent pref = new Intent("android.settings.SYSTEM_UPDATE_SETTINGS"); startActivity(pref);

When you want to use hidden constants to change system settings you must be aware of two things:

  1. in some cases a matching Activity for a given constant may not exist, so ensure you safeguard against this;
  2. for some settings you have to add special permissions to the AndroidManifest.xml file (you can refer to the error messages in the Logcat to discover the permissions needed).

Wednesday 26 March 2014

Hidden Android APIs: listening to incoming SMS messages

In the Android platform there are two classes, SmsManager and SmsMessage, for sending SMS messages; hower there is no official class for receiving them. To be able to receive SMS messages we have to use a hidden API, present in the Android platform but not generally available for developers.
Hidden Android APIs contain several constants, methods, interfaces, etc. that can come in handy in a variety of situations.



To discover hidden Android APIs you can use the following resource:
  • AndroidXRef (http://androidxref.com): this site has indexed all the Android source code and offers a useful search box; however you have to know exactly what you are looking for.

Searching class Telephony from AndroidXRef


In order to make use of the Android hidden APIs, there are two possible scenarios:
  • constants: if you just need to use a hidden constant (for example for broacast actions), you can simply copy them from the Android source code into your app. In this tutorial we will use this technique;
  • methods, classes, interfaces, etc.: hidden methods, classes and interfaces must be compiled, before beeing able to use them. To do this you can either modify the SDK jar file used to compile your app, or make use of the java reflection method, each of which has its pros and cons.

To be able to receive incoming SMS messages we will use the following hidden constants contained in the class telephony-common (you can find them using the utilities listed above):
  • android.provider.Telephony.SMS_RECEIVED”: Intent action used in our BroadcastReceiver to listen to incoming SMS messages;
  • pdus”: constant used to retrieve SMS data from the Intent.

Extract from the class Telephony of the Android source code


Extract from the class Telephony of the Android source code


So here is the code:
  1. declare the use of the RECEIVE_SMS permission in the AndroidManifest.xml file;
  2. declare a BroadcastReceiver in the AndroidManifest.xml file with the intent-filter “android.provider.Telephony.SMS_RECEIVED”;
  3. implement the BroadcastReceiver as follows:


public class SMSReceiver extends BroadcastReceiver {

 public void onReceive(Context context, Intent intent) {
  String action = intent.getAction();

  if(action.equals(“android.provider.Telephony.SMS_RECEIVED”)) {
   Object incomingSMSs[] = (Object[]) intent.getSerializableExtra(“pdus”);
   
   for(Object tmp : incomingSMSs) {
    byte message[] = (byte[]) tmp;
    SmsMessage smsMessage = SmsMessage.createFromPdu(message);
   }
  }
 }
}

Once you have a SmsMessage object, you can use one ot its several methods to retrieve useful info about the SMS received:
smsMessage.getOriginatingAddress();
smsMessage.getMessageBody();
etc.

Wednesday 12 March 2014

Binding Services – part 3 (communication Service -> Activity)

In our previous tutorial about IntentService we saw that a BroadcastReceiver can be used as a means of communication between the Service and the calling client. Hower this method cannot be used for frequent and fast calls, such as for progress updates. For this purpose we have to use a different approach...
For more information about binding Services and the way they are connected to a calling Activity, please refer to my previous tutorials.


SERVICE

First of all we have to define a public interface inside our Service as a means of communication between the Service and the calling Activity:

public interface InterfaceCallback {
   void onProgressUpdate(int progress);
   void onTaskCompleted(MyResult myResult);
}

where MyResult is a user defined class carrying the results of the operation performed by the Service in the background.
The next step is to connect our Service to the calling Activity. To do this, we define an instance variable of the type InterfaceCallback and create a public method that will be called by the calling Activity to connect itself to the Service (the following code goes inside the Service class):

private InterfaceCallback interfaceCallback;
...
public void setInterfaceCallback(InterfaceCallback interfaceCallback) {
   this.interfaceCallback = interfaceCallback;
}

Now our Service is ready to communicate with the calling Activity using the interfaceCallback reference. For example, if we want to notify the updates of a background task (from the onProgressUpdate method of an AsyncTask, for instance) we can call:

interfaceCallback.onProgressUpdate(progress);

In the same way, if we need to communicate that the background operation has been completed and send and object containing the results, we can simply call:

interfaceCallback.onTaskCompleted(myResult);




CALLING ACTIVITY

To make sure that our Activity can receive updates from the Service we have to implement the previously defined interface:

public class CallingActivity extends Activity implements ServiceConnection, MyService.InterfaceCallback {
//see previous tutorial
}

Once we have established a valid connection with the Service, we can register our Activity as a callback (our Activity overrides the InterfaceCallback methods that are triggered by the Service):

@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
  MyService myService = ((MyService.MyBinder) iBinder).getReference();
   myService.setInterfaceCallback(this);
myService.startBackgroundTask();
}

@Override
protected void onPause() {
   super.onPause();
   ...
   if(myService != null) {
      myService.setInterfaceCallback(null);
      unbindService(this);
   }
}

Finally we have to override the methods onProgressUpdate and onTaskCompleted of the implemented InterfaceCallback interface. These methods, as we already saw, are called from the Service to notify the connected Activity about the progress updates and the completion of the background task:

@Override
public void onProgressUpdate(int progress) {
   //code left out for brevity
}

@Override
public void onTaskCompleted(MyResult myResult) {
   //code left out for brevity
}


to be continued...

Wednesday 5 March 2014

Binding Services - part 2 (staying in the foreground)

In our previous tutorial we saw how to create a binding Service and how to bind to it using the Binder pattern. This is a very useful pattern because, once we retrieve a valid reference to our Service, we can use this reference to call Service's methods like any other Java object.



Binding Services usually stay alive until the last client disconnects, calling the unbindService method. When no more clients are connected, the Service is no longer running in the foreground and may be targeted by the system for shutdown (usually when Android is running out of resources).
In order to prevent the system from doing this, we can use the startForeground method. This method makes sure that the Service will stay in the foreground state (usually when executing long running tasks in the background) even if no client is connected.
The only thing to remember is to always call stopForeground, with the parameter true, when the Service has completed its task, otherwise we could potentially waste system resources.



Let's suppose to define a method in our Service class called executeTask, which is meant to perform long running operations. This method is called from our Activity, once a valid reference to our Service is obtained (see previous tutorial for more details), with the following code:

myService.executeTask();

Now we want that our Service will stay in the foreground until the task is completed. We also create a notification reporting that a background operation is running:

public void executeTask() {
   //create the Notification
   Notification.Builder builder = new Notification.Builder(this);
   builder.setContentTitle("Notification title");
   builder.setContentText("Notification text");
   builder.setSmallIcon(R.drawable.icon_for_notification);
   Notification mNotification = builder.build();

   //the Service won't be stopped by the system
   startForeground(1001, mNotification);

  //background operations: left out for brevity
  ...

  //remove the Service from foreground state
  stopForeground(true);
}