Android

Deploy an Android Application

This article follows Getting started in Android programming. We're gonna take back the application we've programmed previously, build it, test it in the SDK and deploy it on a real phone.

If you haven't followed the previous article, you can always use it from the github repository. However it's not the best way to do it ;-)

Sign our applications

Android requires us to sign every application we wish to install, whether it's on the SDK or on a real phone. That system uses a signature in order to check who's the author of the application and establish trust links between all of your applications.

The signature isn't used to check which applications the user can install. It's useless to have a signature certified by an authorized entity. It's perfectly allowed and not atypical for applications to use auto signed certificats.

Some features of the signatures can influence the strategy you'll adopt. Mainly if you plan to deploy several appplciations. The recommanded strategy is one signature for all your applications, for the following reasons :

  • Updates - All versions of one application should be signed with the same certificate. Otherwise, the system won't update the application.
  • Modularity - The system allows us to share the same process between several applications with the same signature, so they would be considered as the same one. With this, you can have several modules for one applications, allowing the user to install one or an other.

One other important thing when you create your signature is the validity period of this one. Indeed when we hit the key's expiration date, your users won't be able to update their applications to newer versions.

Moreover if you plan to publish your application on the Android Market, the key will have to expire after octobre 2033 the 22st.

Development deployment and execution in the SDK

If you've built your project the "standard" way, using the android create project command then you have a local.properties file at the top of it. If you've checked out an other project then you must create it.

This file must contain the path to the Android SDK on your disk. On my current machine this content is the following :

sdk.dir=/home/damien/android-sdk-linux

If it does not exists yet, create it with the appropriate folder.

Then we will build the application's package. For that we'll use ant. This project, is a tool allowing you to build java packages.

For a dev build, enter this in your console :

ant debug

The console display should end with the following :

(master) damien@pcdamien ~/projects/translator $ ant debug

BUILD SUCCESSFUL
Total time: 3 seconds

If you have the BUILD SUCCESSFUL message it means your project has been successfully built.

Now let's execute the virtual machine and install the application on the cellphone. In our previous article, we've seen how to install the Android SDK. Now, let's create a virtual phone.

android create avd -n translator -t android-7

We'll create a new virtual machine which we'll name "translator" and which will have the android-7 target (which is Android 2.1).

Let's execute that virtual machine.

emulator -avd translator &

Now you should see a window with a cellphone starting. Let it start, it can take a few minutes. Once that's done, unlock it. Your new virtual machine is started !

It's virtually linked in USB to your machine. So you can access it distantly. That's what we're gonna do to install the application.

adb install bin/translator-debug.apk

This command will connect us to the cellphone and install the application on it. The console display should be the following :

2216 KB/s (34777 bytes in 0.015s)
    pkg: /data/local/tmp/translator-debug.apk
Success

If, however, you have the following message :

error: device offline

Try to manipulate the cellphone (open the menu for example). It hasn't been detected as active.

Your application has now been installed. Go to the phone's menu, you'll see it's icon.

Production build and installation on a real cellphone

In order to release our application on the market, we must create a signature like we talked in the first part. For that, java offers us a command line tool to manage our keys. It's keytool.

This is how I've generated my own key :

keytool -genkey -v -keystore dmathieu.keystore -alias dmathieu -keyalg RSA -validity 10000

The parameters are the following :

  • -genkey - Tells that we must generate a pair of keys (private and public).
  • -v - Activated the full console render when generating the key.
  • -keystore dmathieu.keystore - The path to the keystore file which will be generated.
  • -storepass - The keystore's password. Don't transmit it that way. If you don't put anything here, it'll be asked when generating the key.
  • -alias dmathieu - An alias for the key. Only the first 8 characters will be taken into account.
  • -keyalg RSA - The key encryption algorithme. The available algorithms are RSA and DSA.
  • -dname - A name describing who has created the key.
  • -validity 10000 - The number of days the key will be valid.
  • -keypass - Your key's password. Don't put it here. It'll be asked.

When executing that command, a file dmathieu.keystore is created. It contains your key. Save it in a place where you're sure it won't be lost but it'll remain safe (I've personnaly stored it in my Google Docs account).

Now, open the file build.properties. In that file, we have to provide the path to your keystore and your key's alias.

key.store=/home/damien.projects/dmathieu.keystore
key.alias=dmathieu

We can now build our application for a release with the key we've just created. In the commande line, let's use to do to.

ant release

This does several things :

  • You application is built, like when doing an ant debug.
  • Your keystore is added to the application in order to authenticate it.
  • The package is optimized in order to speed it's installation.

Your project is now built and ready to be installed on your cellphone. It's available at the path bin/translator-release.apk. You only have to clip your cellphone in USB and install the application on it. You can also, of course, publish it on the Android Market.

Try it by yourself : go to the Android Market, search for the Translator application and install it. That's the application we've been programming in those two articles.

Conclusion

We have, in those two articles on Android, seen how to develop an application, test and install it on a phone. However we're very far from having seen everything in Android app development. We could, for example, add a widget. And many other things !

It's your turn to play now. What applications have you programmed after reading this article ?

Getting started in Android programming

For some weeks now, I've been having fun with java on android. In this article, we're gonna see the basics of android application programming with a sample test application : translator.

What this application does if very simple. You enter the input language, the output and the string you wish to translate. Using Google Translate, the application will translate that string.

Installing the SDK

In order to be able to easily test our application, we're gonna use the Android SDK, allowing us to simulate a cellphone on our computer.

You can download the SDK from the android's official documentation depending of your operating system.

Generate the project

Because we don't use Eclipse, we lose a lot of shortcuts provided by the IDE. But not using it is a choice. You can use the editor of your choice !

We're first gonna start a new project. Android offers a console command for this : android create project

android create project \
    -t <target_ID> \
    -n <your_project_name> \
    -p /path/to/your/project \
    -a <your_activity_name> \
    -k <your_package_namespace>

Several options are required.

  • -t target : It is the version of the android platform we're going to use (here, Android 2.1). To get a list of all the available platformes, you can use android list targets.
  • -name : The name you wish to give to your project.
  • -p path : The directory in which your project will be created.
  • -a activity : The name of the default window which will be opened when we'll launch the application.
  • -k package : The name of the package which will be created. It must follow the naming convention for packages in java.

Let's create our new project which we well name "Translator".

android create project \
    -t 1 \
    -n Main \
    -p ~/projects/translator \
    -a Translator \
    -k com.android.translator

Pure Java : translate a string with Google Translate

For this application, we're going to use an open source library allowing us to make calls to Google Translate : Google API Translate Java. You must include this library in the project we've just created. Download it on Google Code (the .jar file) and put in the folder /libs of your project.

 

We're gonna write an abstraction class for this library right now.

package com.android.translator;
import com.google.api.translate.Language;
import com.google.api.translate.Translate;

public class Translator {
    /*
     * Takes the string to translate and does the work
     */
    public static String translate(String text, Language lang_from, Language lang_to) throws Exception {
        Translate.setHttpReferrer("http//www.dmathieu.com");
        String translatedText = Translate.execute(text, lang_from, lang_to);
        return translatedText;
    }
}

What are we doing ?

package com.android.translator;
import com.google.api.translate.Language;
import com.google.api.translate.Translate;

We define the name of the current package and include the library previously downloaded, which will make the liaison with Google Translate.

Translate.setHttpReferrer("http//www.dmathieu.com");

The Google Translate API requires us to provide a referer, for statistic reasons. You can provide any uri you want here.

String translatedText = Translate.execute(text, lang_from, lang_to);

We get the translated string and we return it.

Then we call Translator.translate in order to translate one string from one language to an other.

Translator.translate("Hello World", Language.ENGLISH,  Language.FRENCH);

Create a Translator.java file in the folder src/com/android/translator and put this code in it.

And ... That's all for now. We're now going to see how to create the application's interface.

Create the Android interface

We're now going to create our application's interface, which will have two select boxes, one text field, one button and our translated string. Any application's interface is to be programmed in XML.

Here's what we have for the screen above, located in the file res/layout/main.xml

<?xml version="1.0" encoding="utf-8">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_weight="1">

    <Spinner 
        android:id="@+id/languages_from"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:prompt="@string/from_languages_prompt" />

    <Spinner 
        android:id="@+id/languages_to"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:prompt="@string/to_languages_prompt" />

    <EditText
        android:id="@+id/text_to_translate"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:background="@android:drawable/editbox_background"
        android:prompt="@string/text_to_translate" />

    <Button
        android:id="@+id/translate_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:text="@string/translate_button" />

    <TextView
        android:id="@+id/translated_text"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />
</LinearLayout>

What happens here ?

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_weight="1">
</LinearLayout>

We define the current window. LinearLayout allows us to define a window with all the elements which will be placed ones after the other.

There are several layout types allowing you to dispose the elements as you wich :

  • AbsoluteLayout : Allows you to place the elements by specifying their x/y coordinates.
  • FrameLayout : Allows you to place one and only one element. If there are several ones, only the last one will be displayed.
  • RelativeLayout : A layout in which everl elements are located one after the other.
  • TableLayout : A layout allowing you to place it's childs in lines or columns.

Then inside this layout, we have several elements.

<Spinner
    android:id="@+id/languages_from"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:prompt="@string/from_languages_prompt" />

The Spinner elements allows you to define a select box. Here, we have two ones. One for the input language and one for the output.

<EditText
    android:id="@+id/text_to_translate"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:background="@android:drawable/editbox_background"
    android:prompt="@string/text_to_translate" />

The EditText element is a text field to be filled by the user.

<Button
    android:id="@+id/translate_button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentRight="true"
    android:text="@string/translate_button" />

In order to tell the application that we've finished typing the phrase and that we're ready to get it's translation, we add here a button.

<TextView
    android:id="@+id/translated_text"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" />

Finally, we add a non editable text field which will contain the translated string.

Translation strings

When, later, we will execute the application we're currently programming, you'll be able to click on the spinner and select a language.

Then you'll the screenshot on the left. As you can see, we have a small phrase telling "pick a language to translate from".

This string is the attribute android:prompt of the spinner.

 
android:prompt="@string/from_languages_prompt"

We call here the I18n translations strings. Let's open res/values/strings.xml

Our file looks like this :

<?xml version="1.0" encoding="utf-8">
<resources>
    <string name="app_name">Translator</string>
    <string name="from_languages_prompt">Choose a language to translate from</string>
    <string name="to_languages_prompt">Choose a language to translate to</string>
    <string name="text_to_translate">The text you wish to translate</string>
    <string name="translate_button">Translate!</string>
</resources>

We put here all our strings and this will be their default translation (usually, english).

You can see than in main.xml, we're making calls to @strings/xxx. As you might have understood, @strings is the name of the file. You can create as many translation files as you wish.

If we wish to add a french translation to our application, we'll have to create res/values-fr/strings.xml Which will contain :

<?xml version="1.0" encoding="utf-8">
<resources>
    <string name="app_name">Translator</string>
    <string name="from_languages_prompt">Langue d'origine</string>
    <string name="to_languages_prompt">Langue de destination</string>
    <string name="text_to_translate">Texte à traduire</string>
    <string name="translate_button">Traduire !</string>
</resources>

It'll automatically get the appropriate translation depending of the phone's parameters.

Filling the spinners

Our spinner's content will be the list of all languages that Google Translate can translate from and to.

We will dynamically fill those spinners. The list is available in the library we're using.

Remember, when you've created your project, you've defined the name of an "Activity" class which is the default window. If you've followed this article to the letter, this activity should be named Main. So let's open src/com/android/translator/Main.java.

It contains an empty activity, allowing only to load the window.

package com.android.translator;
import android.app.Activity;
import android.os.Bundle;

public class HelloAndroid extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
}

The onCreate method is what we're interested in. It's called with a parameter savedInstanceState, which is the current state of the application. We start by calling this onCreate method in the parent class, allowing us to load the require environment by Android for the application.

setContentView(R.layout.main);

R.layout.main is an integer. Every element of your interface (the XML elements defined previously) are defined by Java as integers. You can find each of them with it. And as a constant with this integer is defined every time, you can find it even more easily. Here, R.layout.main is the layout/main.xml file. You can define which interface will be displayed by your activity.

As we'll have to add some content inside our two spinners, we must get their content. They're identified by integers too. In our spinner, we've defined an android:id attribute.

android:id="@+id/languages_from"

So we can get the id of our spinner in the constant R.id.languages_from.

Spinner language_from = (Spinner) findViewById(R.id.languages_from)
Spinner language_to = (Spinner) findViewById(R.id.languages_to)

Ok. Now, let's fill them.

In order to do that, we'll have to create an ArrayAdapter, which will be an array with strings. Every element will be an entry of the select box.

ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

We've created that adapter. Let's add our datas to it.

To add a new element to an adapter, we just need to use the add method.

adapter.add("Ma Valeur");

Here, all our values are located in the Google Translate library. We have to loop through all of them and add them.

for (Language l : Language.values()) {
    adapter.add(l.name());
}

Great ! One last thing however. Our adapter has been created but hasn't been assigned anywhere. We must assign it's values to our two spinners.

languages_from.setAdapter(adapter);
languages_to.setAdapter(adapter);

Which gives us, in fine, to get the content of our two spinners :

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    Spinner language_from = (Spinner) findViewById(R.id.languages_from)
    Spinner language_to = (Spinner) findViewById(R.id.languages_to)

    ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_spinner_item);
    adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

    for (Language l : Language.values()) {
        adapter.add(l.name());
    }

    languages_from.setAdapter(adapter);
    languages_to.setAdapter(adapter);
}

Not too lost ? ;-)

The entire project for this application is available on github

Events : click on the button

Our application is starting to look well. However it's not usable yet. In order to do that, we must be able to click on the button.

We must create a listener on the button click. A function which will be executed at every click.

After the previous code, let's add our listener :

findViewById(R.id.translate_button).setOnClickListener(new View.OnClickListener() {
    public void onClick(View v) {
        String text = ((EditText) findViewById(R.id.text_to_translate)).getText().toString();

        try {
            Language lang_from = Translator.getLanguageString((Spinner) findViewById(R.id.languages_from));
            Language lang_to = Translator.getLanguageString((Spinner) findViewById(R.id.languages_to));

            String translatedText = Translator.translate(text, lang_from, lang_to);
            ((TextView) findViewById(R.id.translated_text)).setText(translatedText);
        } catch(Exception e) {
            ((TextView) findViewById(R.id.translated_text)).setText(e.toString());
        }
    }
});

What are we doing here ?

findViewById(R.id.translate_button)

We get the button element. Then we call, on this element, the setOnclickListener element. This method takes one OnClickListener element. It's a function which will be executed at every click on the button.

String text = ((EditText) findViewById(R.id.text_to_translate)).getText().toString();

Here, we get the text to translate.

try {
    // ****
} catch(Exception e) {
    ((TextView) findViewById(R.id.translated_text)).setText(e.toString());
}

If, for any reason, an error occured when trying to translate the content, we wish to display an error by ourselves and not see the application die.

So, if the internet connection isn't available, it's not possible to translate the string. An exception would be raised. With the try/catch, we intercept this exception and display it's content in the text field.

Language lang_from = Translator.getLanguageString((Spinner) findViewById(R.id.languages_from));
Language lang_to = Translator.getLanguageString((Spinner) findViewById(R.id.languages_to));

We get here the two selected languages. The Translator.getLanguageString must be defined in src/com/android/translator. It contains the following code :

public static Language getLanguageString(Spinner spinner) throws Exception {
    String lang = spinner.getSelectedItem().toString();

    for (Language l : Language.values()) {
        if (l.name() == lang) {
            return l;
        }
    }
    throw new Exception("Unknown language provided : " + lang);
}

With the getSelectedItem method, we get the selected language in the spinner. However the Google Translate library requires that we provide it a Language object. Not a string like we have in the spinner.

So we loop through all the available languages until find the one and return it. If no language is found, we raise an exception (which will be then managed by the try/catch seen earlier).

Let's continue in our action to click on the button.

String translatedText = Translator.translate(text, lang_from, lang_to);

Here, we call the Google Translate library to get the translated string.

((TextView) findViewById(R.id.translated_text)).setText(translatedText);

And finally, we put that string in the appropriate text field.

Conclusion

Sorry for the (too) long article. Our application is now developed. We just have to install it on the SDK to try it. Then on our telephone to use it. That is described in the article Deploy an Android Application