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);
}

Monday, 24 February 2014

Binding Services – part 1

In this tutorial I’ll explain the basics of binding Services. For more information about what Services are and what they are used for please refer to my previous tutorial, IntentServices in Android, that you can find here.


Services in Android can be activated in two ways:
  • you can start a Service through the Context.startService() method;
  • or you can bind to a Service through the Context.bindService() method.

The main difference is that if you bind to a Service, the Service will stay alive until the last client disconnects. In addition to that, if you bind to a Service, instead of starting it, you have a reference to the Service class that can be used to easily call the Service’s methods.
In this first tutorial about binding Services we’ll see how you have to set up your Service class to allow other components to be able to bind to it. To do this you have to implement the onBind method of the Service class, which must return an IBinder object.
In the following example we create an inner class, called MyBinder (extending the Binder class – please note that the Binder class implements the IBinder interface), and we return an object of this class in the onBind method (we can do so because, as already said, the Binder class implements the IBinder interface).

In our MyBinder class we create a method returning a reference to our Service class, which is used in the clients binding to the Service:

public class MyService extends Service {
   //the content of the Service is omitted for brevity
   public void startBackgroundTask() {
      ...
   }
   ...

   //MyBinder class extending Binder
   public class MyBinder extends Binder {
      public MyService getReference() {
         return MyService.this;
      }
   }

   //create an instance of our MyBinder class
   private MyBinder myBinder = new MyBinder();

   //onBind method, returning an instance of our MyBinder
   @Override
   public IBinder onBind(Intent intent) {
return myBinder;
}
}

Now that we have implemented the onBind method in our Service, we can easily bind to the Service through the Context.bindService method.
To begin with, our Activity (or other component binding to the Service) must implement the ServiceConnection interface. The ServiceConnection interface provides a callback method, onServiceConnected, called when a valid connection to the Service is established.

public class MyActivity extends Activity implements ServiceConnection {
...
}

To bind to MyService we can use the following code, typically in the onResume method (this refers to the component, our Activity in this example, that implements the ServiceConnection interface):

Intent intent = new Intent(this, MyService.class);
bindService(intent, this, BIND_AUTO_CREATE);

To unbind from MyService the code is the following (typically in the onPause method):

unbindService(this);

Finally we have to override the onServiceConnected and onServiceDisconneted methods of the ServiceConnection interface. These methods are called, respectively, when MyService is connected/disconnected to/from our Activity.

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

@Override
public void onServiceDisconnected(ComponentName componentName) {
   ...
}

As you can see in the onServiceConnected method we have an IBinder parameter, of the type MyService.MyBinder, because in the onBind method of our Service we return an object of this type (MyService.MyBinder extends Binder and implements the IBinder interface).
Using the iBinder reference, casting it to MyService.Binder and calling the method getReference we obtain a reference to our MyService class. You can then use this reference to call specific methods of MyService, omitted here for brevity, to perform background operations (you have of course to use different threads to perform background tasks, because all methods of the Service class run in the UI thread).

To be continued...

Saturday, 15 February 2014

Using ViewPager to swipe between Fragments in an ActionBar

In this tutorial I'll  briefly explain how to use the ViewPager widget to swipe between different Fragments in an ActionBar.
In our example we not only want to swipe between Fragments using a ViewPager widget: we also need to set up an ActionBar, where each Tab contains a different Fragment, and be able to swipe between them with a smooth animated transition.

In the following example the ViewPager manages the loading of the Fragments, but the widget has to be synchronized with the ActionBar, in other words:

  1. when you swipe to a different Fragment, the ActionBar must select the correct Tab;
  2. when you select a Tab in the ActionBar the ViewPager must select the correct Fragment.


1) XML FILE OF THE MAIN ACTIVITY


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    
    <android.support.v4.view.ViewPager
        android:id="@+id/pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />


</LinearLayout>

As you can see you have to place the ViewPager widget (here named "pager"), which is provided by the android.support.v4 library, in your layout. We set layout_width and layout_height attributes both to "match_parent" in order to make sure that the ViewPager covers the entire display.

2) MAIN ACTIVITY AND FRAGMENTS: IMPORTS

To be able to use the ViewPager widget you have to use the classes provided by the support library, not the standard library:

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentPagerAdapter;

import android.support.v4.view.ViewPager;

In addition to that your main Activity must extend FragmentActivity, not the standard Activity class:

public class MainActivity extends FragmentActivity {
...
}

Make sure to import the Fragment class provided by the support library also in the classes of each Fragment displayed by the ActionBar through our ViewPager:

import android.support.v4.app.Fragment;

...

public class FragmentOne extends Fragment {
...
//the code of the Fragments is omitted for brevity
...
}


3) ONCREATE METHOD OF THE MAIN ACTIVITY

In the onCreate method of the main Activity we have to create the Fragments used to display our data, the ActionBar and setup the ViewPager widget to be able to swipe between different Fragments.
Here is the code:

@Override
protected void onCreate(Bundle savedInstanceState){
   super.onCreate(savedInstanceState);

setContentView(R.layout.main_activity);

    //first we create the Fragments
    firstFragment = new FirstFragment();
secondFragment = new SecondoFragment();
thirdFragment = new ThirdFragment();
fourthFragment = new FourthFragment();

//now we put the Fragments in an array to use them with the ViewPager
arrFragment = new Fragment[4];
arrFragment[0] = firstFragment;
arrFragment[1] = secondFragment;
arrFragment[2] = thirdFragment;
arrFragment[3] = fourthFragment;

    //now we create an adapter between our Fragments and the ViewPager
    //for this purpose we use and instance of our class MyAdapter, which is 
    //explained later
myFragmentPagerAdapter = new MyAdapter(getSupportFragmentManager());
myViewPager = (ViewPager) findViewById(R.id.pager);
    //we load 3 pages in memory on both sides of the current page
    //pages beyond this limit are recreated from the adapter when needed
myViewPager.setOffscreenPageLimit(3); 

myViewPager.setAdapter(myFragmentPagerAdapter);

//here we set up our ActionBar
setupTabs();

myViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
      @Override
public void onPageSelected(int position) {
getActionBar().setSelectedNavigationItem(position);
}
});
}

With the method setOnPageChangeListener we set a listener that will be invoked whenever the page changes or is incrementally scrolled. 
In this case we retrieve a reference of our ActionBar and select the Tab at the position specified by the ViewPager. In this example we have 4 tabs (see next paragraph), so let's select the Tab at the specified position.


4) SETTING UP THE ACTION BAR.

In our example we not only want to swipe between Fragments using a ViewPager widget: we also need to set up an ActionBar, where each Tab contains a different Fragment.
The method setupTabs(), called from onCreate, creates the ActionBar, the 4 Tabs and sets up a connection between the ActionBar and the ViewPager widget.
Basically we register a listener, called every time a Tab is selected (pressed), which forces the ViewPager to change page (load a different Fragment) with a smooth transition:

private void setupTabs() {
final ActionBar actionBar = getActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
ActionBar.TabListener tabListener = new ActionBar.TabListener() {

@Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub

}

@Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
myViewPager.setCurrentItem(tab.getPosition());
}

@Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub

}
  };

     actionBar.addTab(actionBar.newTab().setText(R.string.tab_one).setTabListener(tabListener));
actionBar.addTab(actionBar.newTab().setText(R.string.tab_two).setTabListener(tabListener));
actionBar.addTab(actionBar.newTab().setText(R.string.tab_three).setTabListener(tabListener));
actionBar.addTab(actionBar.newTab().setText(R.string.tab_four).setTabListener(tabListener));

}

5) ADAPTER

To make all things work we need an Adapter class (inner class of the main Activity class) to link our Fragments with the ViewPager widget:

public class MyAdapter extends FragmentPagerAdapter {
private final int PAGE_COUNT = 4;

public MyAdapter(FragmentManager fm) {
super(fm);
}

@Override
public Fragment getItem(int i) {
return arrFragment[i];
}

@Override
public int getCount() {
return PAGE_COUNT;
}

@Override
public CharSequence getPageTitle(int position) {
switch(position) {
case TAB_ONE:
return getResources().getString(R.string.tab_one);
case TAB_TWO:
return getResources().getString(R.string.tab_two);
case TAB_THREE:
return getResources().getString(R.string.tab_three);
case TAB_FOUR:
return getResources().getString(R.string.tab_four);
 
   default:
return null;
}
}
}

where of course:

//constants
private static final int TAB_ONE = 0;
private static final int TAB_TWO = 1;
private static final int TAB_THREE = 2;
private static final int TAB_FOUR = 3;


As you can see from the previous example we have:

  1. a ViewPager widget which loads our Fragments through the class MyAdapter defined above;
  2. an ActionBar which forces the ViewPager to load the correct Fragment each time a Tab is selected (pressed);
  3. a listener linked to our ViewPager which selects the correct Tab whenever the user swipes to a different Fragment.

Sunday, 9 February 2014

"Listening" to preference changes

As you already know in an Android app settings, options and user preferences are generally stored using SharedPreferences objects.
The name of the preference file created by PreferenceManager.getDefaultSharedPreferences() is formed by the package name of your app (com.....) plus the suffix _preferences.


What you might not know (at least I didn't know it until I discovered this week while developing my next app) is that Android uses a single instance of the preference file within the same app. This means that if you open the same preference file twice (for example in 2 different Activities) at the same time, every change that you commit using one object (better apply, because the apply() method works asynchronously) will immediately be reflected in the other object.
So, if you change a preference within an Activity you need a method to notify the other components of your app (Activities, Services, etc.), using the same preference file, tha the change has occured.

To do this you have to implement the SharedPreferences.OnSharedPreferenceChangeListener interface within your Activity, Service, etc.
Basically you have to follow the following steps:

1) implement the SharedPreferences.OnSharedPreferenceChangeListener interface, for example:

public class MyExample extends Activity implements SharedPreferences.OnSharedPreferenceChangeListener {
...
}

2) register and unregister the listener in the appropriate methods, like onResume and onPause:

SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);
pref.registerOnSharedPreferenceChangeListener(this);
String currency = pref.getString("currency", "USD");

and (unregister):

SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);
pref.unregisterOnSharedPreferenceChangeListener(this);

3) override the method onSharedPreferenceChanged in order to listen to preference changes:

@Override
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
   if(key.equals("currency") {
      currency = pref.getString("currency", "USD");
   }
}

Now you know that another component of your app has just changed the value of the currency preference. You may want to perform some actions in response.