In this tutorial we’ll create an interesting android application which has the ability to launch any other app you have installed on your phone. If you’ve ever wanted to know how Android applications perform cross app communication you should read on (this tutorial assumes familiarity with the Android API).
To start off create a new Android application project within Eclipse. Whenever I develop Android apps I usually start with the layout of the application and add functionality via Java classes later. Since our app will display the users installed apps within a ListView widget we have to first declare a layout to hold the ListView itself.
Create a new xml layout for the ListView by right clicking the res/layout folder and adding a new android xml file. Title it “applauncher.xml” and then add the code below to it.
When using ListViews we can setup the overall look of each row by creating an xml layout with a skeleton of the widgets that we want to display in each row of our ListView. Think of the row layout as a “row template”. If you look at the screenshots of the app you can tell that we only need two widgets within our row layout, an ImageView to hold the apps icon and a TextView to display the apps package name.
Create a new xml layout for the ListView rows by right clicking the res/layout folder and adding a new android xml file. Title it “applauncherrow.xml” and add the code below.
Next we’re going to setup the main activity for the launcher app and register the activity in the manifest.
Create a new Java Class and name it “AppLauncher.java”.
Next open up the manifest file for your application and make sure it looks like the code below.
Ok so now that the layouts are coded up and the activity is registered within the manifest open up AppLauncher.java and lets begin.
Lets start off with importing all the necessary libraries needed for our app.
Our app will extend the ListActivity class in order to reduce the boiler plate needed to build a ListView.
However, due to the structure of the app we’ll build the classes needed and stitch them together so just follow along with a text editor for now. To begin we’ll need a class to hold all the useful data we can obtain from a given app. We’ll call it AppInfo, its very basic so go ahead and type it into your editor.
The next class we need is a class that will be used to obtain the application info for the AppInfo class. This class is the bread and butter of our AppLauncher and it together with the AppInfo class can be ported to any application which needs to access other apps via intents.
For the Applications constructor we will pass in the all important PackageManager from the main context.
Below are some getter methods for the package and activities list. The difference between the two is that the package list contains the info about the apps data and the activity list contains info about the intents the app responds to.
The next method is the createPackageList method. All it does is simply extract a list of all the installed apps via the PackageManager that we passed into the constructor. Next we iterate over the list and copy the info we need into a AppInfo object and then shove that object into the ArrayList
Similar to the createPakageList method, createActivityList will return a list with all of the apps installed intent data but unlike createPackageList its only 8 lines of code.
The next two methods are purely for dubugging purposes and can actually be left out but we’ll include them for completeness or in case you use this class in another application.
The next method is needed only because in order to launch an app you need both its package name and its intent name that connects to the main class of the app. However, if you only use the packageList you’ll lack the intent data, so the last method of the Application class adds the class name(intent data) to the packageList making it such that client of the class can have everything bundled up nicely in the packageList instead of having to rely on using both the activity and packageList in unison.
For the method addClassNameToPackageList we’ll iterate over the packageList and for each packageName we’ll find its match within the activityList by packageName and then extract the className from the activityList.
Below is the complete Application class
Remember the AppInfo class that we made and the applauncherrow.xml layout. Well, now we’ll utilize both within the custom ArrayAdapter extension we’ll use to populate the data of our List. ArrayAdapters are used to fill in the data fields of a ListView widget by storing a layout(android uses the term inflate) holding data into a single row of the list.
The constructor for our ArrayAdapter extension…
Being an ArrayAdapter extension means that we have to override the getView method, this is where the applauncherrow layout is populated with data and is used to represent each row of the ListView. To start we’ll reference the applauncherrow layout and inflate it to become a view.
Now that the view is inflated with the applauncherrow.xml layout we can now match the ImageView and TextView with the contents of a AppInfo object in preparation for moving it into the ListView.
Here is the complete ApplicationAdapter class, you should add it to your text file.
We are done with the utility classes so the next step is to add some methods to the AppLauncher class itself. The first one we’re going to add is a method called getApps() which stores the pacakageList from an Applications object and passes it off to Java Runnable to be ran on a thread.
If you look at the getApps() method the last line before the class ends is a method called this.runOnUiThread(returnRes), now what this means is that the main thread will be locked while we pump AppInfo objects into our ListView via the ArrayAdapter. If you are experienced with concurrent programming you might be wondering why lock the mainUIThread, the answer is because our app can’t do anything until all objects have been added to the list. If we by chance were dynamically loading things from the Internet via HTTP requests then we would opt instead for a lazy loader which spawns a thread for each view object pumped into the ListVIew and the list would slowly populate as each item was fetched live from the web. So anyways here is our Runnable method that checks first that the packageList exists and then uses an object from our ApplicationAdapter to fill up our ListView widget.
We’re almost done so now open up your Eclipse IDE to the AppLauncher project and click on the AppLauncher.java class. If you remember from earlier where we left off go ahead and add the data members below to the AppLauncher class; notice the line numbers for reference.
For the onCreate() method there are some things you sould notice. First since AppLauncher is a ListActivity extension it inherits the setListAdapter() method. Second we’ll initialize the viewApps Runnable to call our getApps() within its run(). This means that any thread created with the viewApps as it’s runnable will load up our packages into the ListView. In addition since getApps() locks the mainUIThread users of this app won’t be able to do anything until the thread finishes.
Now that the thread has started and the app has been officially locked, how do we notify the user? The answer is with the android.app.ProgressDialog widget. Remember those loading screen from popular video games, that’s all ProgressDialogs do.
Right now our app can successfully load up a list of Icons and application names but how then do we launch the apps the user touches from our list? The answer is via starting a new intent by overriding the onListItemClick method. So go open up your text file that contains the utility classes and methods and add the onListItemClick() method to it.
Before you run the AppLauncher, be sure to copy and paste the classes and methods into the AppLauncher class so it resembles the complete file below.
Enjoy your AppLauncher.