android

...now browsing by category

 

First list application

Mittwoch, Februar 25th, 2009

Attention: My android posts will now be published on droidnova.com | Link to this article: First list application

Yesterday I started a tutorial I found on the youtube channel of androiddevelopers. The intent of this tutorial is to create an application that shows all contacts by name. You also should be able to click on the name and the phone will start a call to this contact.

The tutorial itself is more than a year old, has some failures and some stuff isn’t available in the same way the tutorial shows. I will show you what you have to do to be successfully program this little android application and I will show you some useful layout improvements.

The first thing you should do is creating a new project in Eclipse (or in your IDE). I chose “de.warrenfaith.android.contacts” as package and “ListContacts” as activity name.
After you have done this, you should open the main.xml to modify the layout.

The first XML node is responsible for the entire applications. Every UI element you want to display should be setup here.

1
2
3
4
5
6
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
</LinearLayout>

Line 1 is the normal XML DocType.
Line 2 defines the LinearLayout node.
Line 3 defines the orientation which is horizontal, so that every child element will be displayed from left to right.
Line 4-5 defines that this layout will fill the whole parent which is the screen because it is the first defined element.
Line 6 closes the layout element.

Now lets add a static image for our list. We will use the default icon which every new project has in his res/drawable directory.
We need to add this to our main.xml this way:

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <ImageView android:src="@drawable/icon"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</LinearLayout>

New are the lines 6 to 8.
Line 6 creates a new node for ImageView and defines the source of the image. @drawable is the “link” to the res/drawable directory to look for a image named icon
Line 7-8 defines the layout which is here set to wrap the content so it just use the space the image really needs.

The next step is to setup the TextViews for the contact name and the TextViews for the phone number.
The contact name should stay above the phone number, so we need to define the next LinearLayout with the orientation as a child node of the first LinearLayout. The main.xml should now look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <ImageView android:src="@drawable/icon"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    <LinearLayout
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent">
    </LinearLayout>
</LinearLayout>

Now we want to fill this child node with another LinearLayout with horizontal orientation to have the label “Name:” and the contact name in one line.
First the contact name, so lets cut and paste the following XML snippet below:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    android:orientation="horizontal"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Name: " />
    <TextView android:id="@+id/contact_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</LinearLayout>

Now the phone number:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    android:orientation="horizontal"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Phone: " />
    <TextView android:id="@+id/phone_number"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</LinearLayout>

Confused? I don’t hope so, but here is an image to realize what is what:

ListView Schema

ListView Schema

And here is the final main.xml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <ImageView
        android:src="@drawable/icon"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
    />
    <LinearLayout
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent">
        <LinearLayout
            android:orientation="horizontal"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Name: "
            />
            <TextView android:id="@+id/contact_name"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
            />
        </LinearLayout>
        <LinearLayout
            android:orientation="horizontal"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Phone: "
            />
            <TextView android:id="@+id/phone_number"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
            />
        </LinearLayout>
    </LinearLayout>
</LinearLayout>

Everybody who is thinking about webdesign and div-layout is understanding the android user interface layout.

Now it is time to create the Activity, in our case, the ListActivity.
My activity class is named ListContacts and looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
package de.warrenfaith.android.contacts;
 
import android.app.Activity;
import android.os.Bundle;
 
public class ListContacts extends ListActivity {
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
}

First of all we can delete the line 11 because its just not needed in our application.
The next step is to create a cursor which can iterate over our contacts on the phone. To get the cursor we use the ContentResolver and start a query.

1
2
Cursor cursor = getContentResolver().query(People.CONTENT_URI, null, null, null, null);
startManagingCursor(cursor);

The next step is to create a mapping. First we define the colums we want to use from the query.

1
String[] columns = new String[] {People.NAME, People.NUMBER};

The next step is to define the destination on which the values from the query are mapped.

1
int[] names = new int[] {R.id.contact_name, R.id.phone_number};

Now we create a SimpleCursorAdapter and use it.

1
2
myAdapter = new SimpleCursorAdapter(this, R.layout.main, cursor, columns, names);
setListAdapter(myAdapter);

The variable myAdapter is a class variable so we can later access it easily.

1
private SimpleCursorAdapter myAdapter;

The actual Activity should look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package de.warrenfaith.android.contacts;
 
import android.app.ListActivity;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.Contacts.People;
import android.widget.SimpleCursorAdapter;
 
public class ListContacts extends ListActivity {
 
    private SimpleCursorAdapter myAdapter;
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Cursor cursor = getContentResolver().query(People.CONTENT_URI, null, null, null, null);
        startManagingCursor(cursor);
 
        String[] columns = new String[] {People.NAME, People.NUMBER};
        int[] names = new int[] {R.id.contact_name, R.id.phone_number};
 
        myAdapter = new SimpleCursorAdapter(this, R.layout.main, cursor, columns, names);
        setListAdapter(myAdapter);
    }
}

Now we can implement the click and call feature.
Lets override the onListItemClick() method from the super class ListActivity.

1
2
3
4
@Override
protected void onListItemClick(ListView listView, View view, int position, long id) {
    super.onListItemClick(listView, view, position, id);
}

First lets create an Intent object to make a call.

1
Intent intent = new Intent(Intent.ACTION_CALL);

Now lets determine on which element we have clicked:

1
2
Cursor cursor = (Cursor) myAdapter.getItem(position);
long phoneId = cursor.getLong(cursor.getColumnIndex(People.PRIMARY_PHONE_ID));

Line 1 set the cursor to the correct element using the parameter “position”.
Line 2 gets the phone id, which seems to be the primary key of each contact.

Now we can set the data for the intent and start the activity.

1
2
intent.setData(ContentUris.withAppendedId(Phones.CONTENT_URI, phoneId));
startActivity(intent);

Finally you should have this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package de.warrenfaith.android.contacts;
 
import android.app.ListActivity;
import android.content.ContentUris;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.Contacts.People;
import android.provider.Contacts.Phones;
import android.view.View;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
 
public class ListContacts extends ListActivity {
 
    private SimpleCursorAdapter myAdapter;
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Cursor cursor = getContentResolver().query(People.CONTENT_URI, null, null, null, null);
        startManagingCursor(cursor);
 
        // start mappings
        String[] columns = new String[] {People.NAME, People.NUMBER};
        int[] names = new int[] {R.id.contact_name, R.id.phone_number};
 
        myAdapter = new SimpleCursorAdapter(this, R.layout.main, cursor, columns, names);
        setListAdapter(myAdapter);
    }
 
    @Override
    protected void onListItemClick(ListView listView, View view, int position, long id) {
        super.onListItemClick(listView, view, position, id);
 
        Intent intent = new Intent(Intent.ACTION_CALL);
        Cursor cursor = (Cursor) myAdapter.getItem(position);
        long phoneId = cursor.getLong(cursor.getColumnIndex(People.PRIMARY_PHONE_ID));
        intent.setData(ContentUris.withAppendedId(Phones.CONTENT_URI, phoneId));
 
        startActivity(intent);
    }
}

The last thing you have to do is to grant your application the permission to start the calls and to read the contacts of your phone.
You can do this by add some snippets to your AndroidManifest.xml

1
2
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.CALL_PHONE" />

The file itself should now look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="de.warrenfaith.android.contacts"
      android:versionCode="1"
      android:versionName="1.0.0">
    <uses-permission android:name="android.permission.READ_CONTACTS" />
    <uses-permission android:name="android.permission.CALL_PHONE" />
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".ListContacts"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

Now you can compile and run the application on your emulator or device.

The next step will be to use the contact picture you once added in the contact.

Installing foreign application on Android Emulator

Dienstag, Februar 24th, 2009

Attention: My android posts will now be published on droidnova.com | Link to this article: Set up SD card for your android emulator

After reading a lot of blogs, tutorials, developer guides and miscellaneous stuff I started to wonder, if installing an application without the android market and without the sdk tools (ignore the emulator please :D ) is possible.

Some mailing list entries and blogs mentioned hacks to do so, but I couldn’t believe it. So whats the right thing to do in this case? Correct: lets try it!

The first thing I needed was an application to install so I took the one I created in my first tutorial: HelloAndroid.
I uploaded it on my web space, started the emulator and typed the URL of the apk in the browser. Android told me instantly that I need to install a SD card. Ok, never done that so far, so I looked and found a page about the emulator setup.
So I started creating a SD card image with the command line (could take some time…)
mksdcard 2048M sdcard.iso

Then I started the emulator with the parameter for the SD card image:
emulator -sdcard sdcard.iso

If you store your SD card image not in the same directory as the emulator start script, you need to add the path to the image like that:
emulator -sdcard /path/to/androidsdk/tools/sdcard.iso

Now I checked if the emulator has found my SD card. Done that with Menu -> Settings -> SD card & phone storage and read: 2040 MB total space on SD card was found.

After this setup I could easily download my apk-file from my websapce, install it and run it.

PS: A warning occurred as I tried it a second time but the warning was just to remind me this application was already installed and if I am sure to replace the existing with the new one.

Get the ActivityManager for MemoryInfo

Sonntag, Februar 22nd, 2009

Attention: My android posts will now be published on droidnova.com

During my first steps of Android programming, i want to know how much memory the device has or how much is really used.
In the Android API I found the ActivityManager class which has a inner class MemoryInfo. Simply instantiation of the ActivityManager failed because there is no visible constructor.
Searching the web gave no answers only open questions from other developer. So I looked further and I found a method of the Activity class called getSystemService(String name). With a constant from Context.ACTIVITY_SERVICE as parameter it returns me an Object I can cast to ActivityManager. With an instance from MemoryInfo I could now get the information I wanted.
At the moment I don’t know how to display the memory information in the UI, but I just started :D
Here is my short code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package de.warrenfaith.android.memory;
 
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManager.MemoryInfo;
import android.content.Context;
import android.os.Bundle;
 
public class MemoryTest extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityManager mgr = (ActivityManager) super.getSystemService(Context.ACTIVITY_SERVICE);
        MemoryInfo memInfo = new ActivityManager.MemoryInfo();
        mgr.getMemoryInfo(memInfo);
        setContentView(R.layout.main);
    }
}
Stoppt die Vorratsdatenspeicherung! Jetzt klicken & handeln!Willst du auch bei der Aktion teilnehmen? Hier findest du alle relevanten Infos und Materialien: