Mobile

Google IO 2011 App

Android: Implement a Dashboard Layout Activity

17
Google IO 2011 App

Google I/O 2011 App

In this post I will show you the steps to quickly implement a dashboard activity in your app starting with the open source, apache licence DashboardLayout by romannurik from the Google I/O app.

A dashboard is the welcoming screen of your app. It provides a starting point for the user. A dashboard can be static or dynamic, e.g. you can incorporate live wallpapers or changing content such as news items.

On a category dashboard, entrance points to content are displayed in several categories. The categories are represented by an icon and a title, and lie full screen in a grid orientation. This lay-out allows the user to find content faster.

Android Patterns

First start by creating a new class DashboardLayout.java within your project and copy and pasting the code from github into it. You’ll need to change package com.google.android.apps.iosched.ui.widget; to the package where it is located in your project and press ctrl+shift+O in Eclipse to re-organise imports.

Next up create a new class, DashboardActivity that extends Activity – in my case it extends GDActivity as I am also using the Greendroid library – for quick implementation of an ActionBar but yours can just extend Activity.

Add this new Activity to your AndroidManifest.xml and make it the main one, (mine is in the .ui package, if yours is in the root or elsewhere then remove .ui and change as appropriate):

<activity android:name=".ui.DashboardActivity" android:label="@string/app_name">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

Create a new xml layout, dashboard.xml. Where mine has the tag <com.samcoles.layout.DashboardLayout> you will need to change the part prefixing DashboardLayout to the package where it is located. You may notice they all use the same @drawable, dashboard_buton_add – you will want to change this per button to something more relevant but for simplicity, here they are all going to use the same graphics.

<?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"
    >

    <com.samcoles.layout.DashboardLayout
	    xmlns:android="http://schemas.android.com/apk/res/android"
	    android:orientation="vertical"
	    android:layout_width="fill_parent"
	    android:layout_height="fill_parent">

	    <Button android:id="@+id/dashboard_button_add"
	        style="@style/DashboardButton"
	        android:text="@string/activity_add"
	        android:drawableTop="@drawable/dashboard_button_add" />

        <Button android:id="@+id/dashboard_button_viewall"
	        style="@style/DashboardButton"
	        android:text="@string/activity_viewall"
	        android:drawableTop="@drawable/dashboard_button_add" />

        <Button android:id="@+id/dashboard_button_manage"
	        style="@style/DashboardButton"
	        android:text="@string/activity_manage"
	        android:drawableTop="@drawable/dashboard_button_add" />

        <Button android:id="@+id/dashboard_button_personalbests"
	        style="@style/DashboardButton"
	        android:text="@string/activity_personalbests"
	        android:drawableTop="@drawable/dashboard_button_add" />    

    </com.samcoles.layout.DashboardLayout>

</LinearLayout>

You’ll notice in the dashboard.xml layout there are a number of @string, @style and @drawable resources referenced. Create or replace the string resources within strings.xml, which is created by default in Eclipse when you create a project. Also in your /res/values folder create a new file style.xml and in here place the style for DashboardButton:

<?xml version="1.0" encoding="utf-8"?>
<resources>
	<style name="DashboardButton">
		<item name="android:layout_gravity">center_vertical</item>
		<item name="android:layout_width">wrap_content</item>
		<item name="android:layout_height">wrap_content</item>
		<item name="android:gravity">center_horizontal</item>
		<item name="android:drawablePadding">2dp</item>
		<item name="android:textSize">14sp</item>
		<item name="android:textStyle">bold</item>
		<item name="android:textColor">#ff0000</item>
		<item name="android:background">@null</item>
	</style>
</resources>

Next up create a folder /res/drawable and in here create a new file, dashboard_button_add.xml (you will need to create multiple different xml files for each button in here and reference them from the dashboard.xml layout. As I mentioned before, we are using the same one for all four buttons here.

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/dashboard_add_button_selected"
        android:state_focused="true"
        android:state_pressed="true" />
    <item android:drawable="@drawable/dashboard_add_button_selected"
        android:state_focused="false"
        android:state_pressed="true" />
    <item android:drawable="@drawable/dashboard_add_button_selected" android:state_focused="true" />
    <item android:drawable="@drawable/dashboard_add_button_default"
        android:state_focused="false"
        android:state_pressed="false" />
</selector>

Create and add the graphics referenced above to your /res/drawable-hdpi folder. These are add_button_default.png and add_button_selected.png. I made mine the same size as the ones in the Google I/O app, 144px * 96px but the proportions aren’t fixed using DashboardLayout.

Here they are in all their glory. The best part about them is that I didn’t even manage to get the horizontal line straight. Once these placeholders are in you can update them later with proper graphics as well as create new @drawable xml for each different button on the dashboard.

add_button_default.png

add_button_default.png

add_button_selected.png

add_button_selected.png

Next up, head back to your DashboardActivity. Within this class create a new inner class, DashboardClickListener that implements the OnClickListener interface. Implement the method onClick(). Here you can call getId() on the View passed to the handler, to get the Id of which button was clicked – this is specified in your dashboard.xml layout. Put this in a switch block and you can then handle the click event however you like, it’s likely you’ll want to just start a new activity with each, here’s mine:

private class DashboardClickListener implements OnClickListener {
	@Override
	public void onClick(View v) {
		Intent i = null;
		switch (v.getId()) {
			case R.id.dashboard_button_add:
				i = new Intent(DashboardActivity.this, AddCapture.class);
				break;
			case R.id.dashboard_button_viewall:
				i = new Intent(DashboardActivity.this, ViewAll.class);
				break;
			case R.id.dashboard_button_manage:
				i = new Intent(DashboardActivity.this, Manage.class);
				break;
			case R.id.dashboard_button_personalbests:
				i = new Intent(DashboardActivity.this, PersonalBests.class);
				break;
			default:
				break;
		}
		if(i != null) {
			startActivity(i);
		}
	}
}

Last but certainly not least, in your overridden onCreate() method in DashboardActivity, you need to create an instance of DashboardClickListener and attach this to each button. Below is my full overridden onCreate() method – setActionBarContentView() is just the GreenDroid alternative to setContentView() – you can use the latter instead.

@Override
public void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setActionBarContentView(R.layout.dashboard);

	//attach event handler to dash buttons
	DashboardClickListener dBClickListener = new DashboardClickListener();
	findViewById(R.id.dashboard_button_add).setOnClickListener(dBClickListener);
	findViewById(R.id.dashboard_button_viewall).setOnClickListener(dBClickListener);
	findViewById(R.id.dashboard_button_manage).setOnClickListener(dBClickListener);
	findViewById(R.id.dashboard_button_personalbests).setOnClickListener(dBClickListener);
}

If all went well, you should now have a working dashboard! Remember you can have more or less buttons on your dashboard, but 6 options appears to be the standard max across most Android Apps I’ve seen and used. Aside from the Google I/O 2011 app, other examples include LinkedIn and tastecard.

Dashboard Screenshot

Dashboard Screenshot, New Capture being pressed

A working example project based on this post can be found on github.

Gmail Logo

Android: Send email with pre-populated fields

1

Within the AppInfoActivity of my current project, I have a button to send an email to the developer (me!). This button creates an Intent and uses Intent.putExtra to pre-populate the Email, subject and body of the email.

Initially my Email “To” field wasn’t populating – if this is happening to you, it’s probably because it’s expecting a String array (to allow for multiple email addresses) and not a single String object, you’ll notice this is different in the onClick handler below:

public void onEmailButtonClick(View v) {
    final Intent emailIntent = new Intent(Intent.ACTION_SEND);
    emailIntent.setType("plain/text");
    emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[] { getString(R.string.app_email_address) });
    emailIntent.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.app_info_email_subject));
    emailIntent.putExtra(Intent.EXTRA_TEXT, getString(R.string.app_info_email_body));
    startActivity(emailIntent);
}

and for completeness, here’s the xml for the string resources referenced:

<?xml version="1.0" encoding="utf-8"?>
<resources>
	<string name="app_info_email_subject">Feedback on someOldApp</string>
	<string name="app_info_email_body">Hi someOldApp,</string>
	<string name="app_email_address">someoldapp@samcoles.co.uk</string>
</resources>
Android

Android: Get number of rows in SQLite Database Table

1

Here’s a little function from my Database Adapter class in the app I’m working on. It returns the number of rows in the “Places” table from my database.

It does this using a SQLiteStatement object, much simpler and cleaner than getting a Cursor using SQLiteDatabase.rawQuery().

A SQLiteStatement can be used for database queries that return “1×1 result sets”, that is one row with one column – a single value.

private static final String DB_TABLE_PLACES = "Places";
private SQLiteDatabase mDatabase;

private long fetchPlacesCount() {
    String sql = "SELECT COUNT(*) FROM " + DB_TABLE_PLACES;
    SQLiteStatement statement = mDatabase.compileStatement(sql);
    long count = statement.simpleQueryForLong();
    return count;
}
Passing Data Between Activities

Android: Passing data between Activities

5

With the Android framework, data can be passed between different Activities by adding it to the Intent object before starting the new Activity, and then retrieving it using a Bundle object. We will demonstrate this by creating a small demo with two Activities, the first activity, TextInputActivity will allow the user to type in some text and tap a button. Tapping the button will open ViewTextActivity, taking the inputted text with it in the Intent, this text will be retrieved and displayed in ViewTextActivity.

This demo will cover the method for primitive data types, we’ll cover passing your own data types/objects in another post.

First we will get the layouts out the way, both are very simple.
text_input_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:orientation="vertical">
  <EditText
  	android:id="@+id/the_input"
  	android:layout_width="250dp"
  	android:layout_height="wrap_content"
  	android:layout_weight="1"/>
  <Button
  	android:id="@+id/the_button"
  	android:layout_width="wrap_content"
  	android:layout_height="wrap_content"
  	android:text="Go to next Activity"
  	android:onClick="goToNextActivity"/>
</LinearLayout>

text_view_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content">
  <TextView
  	android:id="@+id/the_text"
  	android:layout_width="wrap_content"
  	android:layout_height="wrap_content"
  	android:textSize="10pt"/>
</LinearLayout>

Now we’ll create TextInputActivity, this is declared as the main activity in the AndroidManifest.xml. In here we’ll add the onClick handler, goToNextActivity() that’s referenced in the xml layout. Within this method, first we’ll get a reference to the EditText and extract the text from it to a String. Then we create a new Intent object to ViewTextActivity. We’ll call Intent.putExtra() to add the String to the Intent. the first parameter is the name we’ll use to retrieve it later – this is a constant that we’ll declare in ViewTextActivity so don’t worry about the error for now. We’ll just need to remember to add this constant and give it public access in TextViewActivity. Finally, call startActivity() passing it our Intent to start the new Activity.

TextInputActivity.java

package samcoles.bundleexample;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;

public class TextInputActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.text_input_layout);
    }

    public void goToNextActivity(View v) {
        String theText = null;
        //first get the EditText View and extract the text...
        EditText theInput = (EditText)findViewById(R.id.the_input);
        if(theInput != null) {
            theText = theInput.getText().toString();
        }
        //create a new Intent
        Intent i = new Intent(this, ViewTextActivity.class);
        //add theText to the intent
        i.putExtra(ViewTextActivity.TEXT_DATA, theText);
        //start the activity
        startActivity(i);
    }
}

Next we’ll add our second Activity, ViewTextActivity. Remember to add this to your AndroidManifest.xml or your app will crash!

First we’ll define the public constant TEXT_DATA that we used in TextInputActivity.

public static final String TEXT_DATA = "textData";

Then in the overridden onCreate() method we’ll get a reference to the Bundle object in the Intent by calling getIntent().getExtras(). We’ll then call Bundle.getString(), passing the TEXT_DATA constant to retrieve our value. Finally we’ll get a reference to the TextView in our layout and call TextView.setText() passing our String.

ViewTextActivity.java

package samcoles.bundleexample;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class ViewTextActivity extends Activity {
    public static final String TEXT_DATA = "textData";

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.text_view_layout);    

        Bundle extras = getIntent().getExtras();
        if(extras != null) {
            String theText = extras.getString(TEXT_DATA);
            if(theText != null) {
                TextView t = (TextView)findViewById(R.id.the_text);
                if(t != null) {
                    t.setText(theText);
                }
            }
        }
    }
}

Here’s a screenshot of each activity in the demo in action:

Passing Data Between Activities

Passing Data Between Activities

android_logo

Android SharedPreferences

8

A quick and easy way to store data that needs to be persistent across different user sessions, and accessible by your whole application and not just one activity, is by using the SharedPreferences class. This can be used for example to store your app’s settings.

To demonstrate we’ll create a small demo with a CheckBox and an EditText box in the layout. The state of these will be saved when the app goes out of focus and restored when resumed.

First up, the very simple layout with the CheckBox and EditText.

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">
    <CheckBox
    	android:id="@+id/prefsdemo_checkbox"
    	android:layout_width="fill_parent"
    	android:layout_height="wrap_content"
    	android:textSize="6pt"/>
	<EditText
		android:id="@+id/prefsdemo_edittext"
		android:layout_width="250dp"
		android:layout_height="wrap_content"/>
</LinearLayout>

In your activity, you will need objects to reference the EditText and Checkbox. You will also need one for SharedPreferences. Lastly you will need a string constant for the name of the SharedPreferences (your app can have more than one). I’ve called mine “SharedPrefsDemoPreferences” – you can choose something more meaningful. This constant is public so you can access it from elsewhere in your app. Put these in at the top of your activity class.

public static final String PREFS_NAME = "SharedPrefsDemoPreferences";

private SharedPreferences mPrefs;
private EditText mEditText;
private CheckBox mCheckBox;

Override the onCreate() method and assign references to your SharedPreferences, EditText and Checkbox objects. Call getSharedPreferences() with the string constant you just defined. mEditText and mCheckBox are defined in our main.xml layout and we get references to these using findViewById().

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

    mPrefs = getSharedPreferences(PREFS_NAME, 0);

    mEditText = (EditText)findViewById(R.id.prefsdemo_edittext);
    mCheckBox = (CheckBox)findViewById(R.id.prefsdemo_checkbox);
}

Next we will override onResume(). This is called when the activity is resumed after going out of focus, as well as after onCreate() is finished. The code we’ll put here will set the values for our CheckBox and EditText using the values from our SharedPreferences object. Before we do this, add these two new string constants beneath PREFS_NAME. These are the names of the data we’ll be storing.

public static final String PREF_STRING = "PrefString";
public static final String PREF_BOOL = "PrefBool";

The first parameter for SharedPreferences.getString() and SharedPreferences.getBoolean() is the string name of the data we want to get. We pass the constants we just defined. The second represents default values to use if the values do not exist (which as yet, they do not). We take the values from these calls and use them to set the values of our EditText and CheckBox.

@Override
protected void onResume() {
    mEditText.setText(mPrefs.getString(PREF_STRING, "EditText"));
    mCheckBox.setChecked(mPrefs.getBoolean(PREF_BOOL, false));
    super.onResume();
}

Next up we’ll be overriding onPause(). It’s called when the activity goes out of focus or before the activity is about to be destroyed. Here we’ll want to update the SharedPrefences values.

@Override
protected void onPause() {
    Editor e = mPrefs.edit();
    e.putBoolean(PREF_BOOL, mCheckBox.isChecked());
    e.putString(PREF_STRING, mEditText.getText().toString());
    e.commit();

    Toast.makeText(this, "Settings Saved.", Toast.LENGTH_SHORT).show();
    super.onPause();
}

To explain. First we get the Editor object for our SharedPreferences, we use putBoolean() and putString() to put the values from the CheckBox and EditText into the object. Lastly we call commit() to save the new values.

We also give the user a toast notification to let them know it was saved.

Here’s the java class for this demo activity in full.

SharedPrefDemo.java

package samcoles.sharedprefsdemo;

import android.app.Activity;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Bundle;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.Toast;

public class SharedPrefsDemo extends Activity {

    public static final String PREFS_NAME = "SharedPrefsDemoPreferences";

    public static final String PREF_STRING = "PrefString";
    public static final String PREF_BOOL = "PrefBool";

    private SharedPreferences mPrefs;
    private EditText mEditText;
    private CheckBox mCheckBox;

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

        mPrefs = getSharedPreferences(PREFS_NAME, 0);

        mEditText = (EditText)findViewById(R.id.prefsdemo_edittext);
        mCheckBox = (CheckBox)findViewById(R.id.prefsdemo_checkbox);
    }

    @Override
    protected void onResume() {
        mEditText.setText(mPrefs.getString(PREF_STRING, "EditText"));
        mCheckBox.setChecked(mPrefs.getBoolean(PREF_BOOL, false));
        super.onResume();
    }

    @Override
    protected void onPause() {
        Editor e = mPrefs.edit();
        e.putBoolean(PREF_BOOL, mCheckBox.isChecked());
        e.putString(PREF_STRING, mEditText.getText().toString());
        e.commit();

        Toast.makeText(this, "Settings Saved.", Toast.LENGTH_SHORT).show();
        super.onPause();
    }

}

Try modifying the EditText and CheckBox, exiting and then coming back to the application later – the values will remain the same.

Custom Toast Notification

Android Custom Toast Notification

2

You may recognise Toast notifications from Android applications you have used, they look like this:

Android Toast Notification

Android Toast Notification

These are very easy to implement, like so:

Toast.makeText(this, "This is toast.", Toast.LENGTH_LONG).show();

This will display the toast notification immediately. You will also need to import android.widget.Toast in your activity, pushing ctrl+shift+o in Eclipse will take care of this for you.

But what about notifications with the same behaviour, but a customised layout? Perhaps with images? To demonstrate I’ve set up an activity with a button and an onClick handler. Here are the layout xml and Activity class.

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:paddingTop="10px"
    >
	<Button
		android:id="@+id/button"
		android:layout_width="wrap_content"
		android:layout_height="wrap_content"
		android:text="Push For Toast"
		android:onClick="buttonClicked">
	</Button>
</LinearLayout>

CustomToastDemo.java

package samcoles.customtoastdemo;
package samcoles.customtoastdemo;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;

public class CustomToastDemo extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }

    public void buttonClicked(View view) {

    }
}

First things first with your custom toast, you will need to create an xml layout for it. Add this to your /res/layout/ folder. You are practically unlimited in what you can do with this. I’ve put the application’s icon to the left with some text to the right. I’ve also made the background partly transparent so you can see what’s behind.

custom_toast.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/toast_layout_root"
     android:orientation="horizontal"
     android:layout_width="fill_parent"
     android:layout_height="fill_parent"
     android:paddingLeft="10dp"
     android:paddingRight="10dp"
     android:layout_marginLeft="10dp"
     android:layout_marginRight="10dp">
     <LinearLayout
    	android:orientation="horizontal"
    	android:layout_width="fill_parent"
    	android:layout_height="fill_parent"
    	android:background="#DAAA"
    	android:paddingTop="5dp"
    	android:paddingBottom="5dp">
		    <ImageView
		    	android:id="@+id/toastImage"
		    	android:layout_width="wrap_content"
		        android:layout_height="fill_parent"
		        android:src="@drawable/icon"
		        android:layout_marginRight="10dp"
		        />
		    <TextView
		    	 android:id="@+id/toastText"
		         android:layout_width="wrap_content"
		         android:layout_height="fill_parent"
		         android:textSize="7pt"
		         android:textStyle="bold"
		         android:textColor="#000"
		         android:layout_gravity="center_vertical"
		         android:gravity="center"
		         android:layout_marginRight="10dp"
		         />
    </LinearLayout>
</LinearLayout>

To create and show the custom toast, I’ve modified the onClick handler for the button in the CustomToastDemo activity.

    public void buttonClicked(View view) {
        //get the LayoutInflater and inflate the custom_toast layout
        LayoutInflater inflater = getLayoutInflater();
        View layout = inflater.inflate(R.layout.custom_toast, (ViewGroup) findViewById(R.id.toast_layout_root));

        //get the TextView from the custom_toast layout
        TextView text = (TextView) layout.findViewById(R.id.toastText);
        text.setText("This is my custom toast");

        //create the toast object, set display duration,
        //set the view as layout that's inflated above and then call show()
        Toast t = new Toast(getApplicationContext());
        t.setDuration(Toast.LENGTH_LONG);
        t.setView(layout);
        t.show();
    }

To explain the above, first we instantiate the layout using the application context’s LayoutInflater. We then set the Text to “This is my custom toast”. You could also set the image to something more specific here if wanted. Next up we create the Toast object using the custom layout and finally call show() to display it.

and here’s how that looks:

Custom Toast Notification

Custom Toast Notification

Android ListActivity with a header or footer

8

This post will show you how to go about implementing a ListActivity with a header or footer that does not follow the same layout as the list rows. A well known and obvious example of this is the main screen on the Android Market.

First, create a class that extends ListActivity:

ListWithHeader.java

package samcoles.listwithheader;

import android.app.ListActivity;
import android.os.Bundle;

public class ListWithHeader extends ListActivity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.list_main);
    }
}

Remember to ensure you have added this activity to your AndroidManifest.xml.

Next up you’ll need to create the list_main layout that’s set in the above ListActivity within /res/layout. Remember the <ListView> must have id=”@+id/android:list” and you should also have a view with id=”@+id/android:empty” to display when there’s no items in the list. Your ListActivity will go looking for these and your app will crash when loading this activity if you don’t have them. If you’re not aware of this then the debugger can be a bit unhelpful. The TextView uses a string resource, empty_list that you’ll need to remember to add too if you’re using this.

here’s the list_main layout:

list_main.xml

<?xml version="1.0" encoding="utf-8"?>	

<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:orientation="vertical">
  <ListView
  	android:id="@+id/android:list"
  	android:layout_width="fill_parent"
  	android:layout_height="wrap_content"
  	android:scrollbars="none"/>
  <TextView
  	android:id="@+id/android:empty"
  	android:layout_width="wrap_content"
  	android:layout_height="wrap_content"
  	android:text="@string/empty_list" />
</LinearLayout>

You’ll also need a layout for the header, note that this below references a couple of string resources and an image resource:

list_header.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:id="@+id/header_layout_root"
  android:background="#ffffff"
  android:orientation="vertical">
	<TextView
    	android:layout_width="fill_parent"
    	android:layout_height="wrap_content"
	    android:text="@string/app_name"
	    android:background="#000000"
	    android:textColor="#ffffff"
	    android:textSize="28dp"
	    android:gravity="center_horizontal"
	    android:paddingTop="10dp"
	    android:paddingBottom="10dp">
	</TextView>
    <RelativeLayout
	    android:layout_width="fill_parent"
	    android:layout_height="wrap_content">
	  	<ImageView
			android:id="@+id/sample_image"
			android:layout_width="fill_parent"
			android:layout_height="wrap_content"
			android:adjustViewBounds="true"
			android:src="@drawable/sample_image"
			android:scaleType="fitXY">
		</ImageView>
		<TextView
			android:id="@+id/sample_title"
			android:text="@string/sample_text"
			android:layout_width="wrap_content"
			android:layout_height="wrap_content"
			android:textColor="#ffffffff"
			android:textSize="12dp"
			android:background="#AA000000"
			android:padding="5dp"
			android:layout_alignParentLeft="true"
			android:layout_alignBottom="@id/sample_image">
		</TextView>
	</RelativeLayout>
</LinearLayout>

Next go back to your ListActivity class and it’s time to put in the code to add the header to your list, place this just below the call to setContentView():

ListView lv = getListView();
LayoutInflater inflater = getLayoutInflater();
View header = inflater.inflate(R.layout.list_header, (ViewGroup) findViewById(R.id.header_layout_root));
lv.addHeaderView(header, null, false);

To explain the above, first we call getListView() to get the activity’s ListView and assign this to an object. We then call getLayoutInflater() and do the same – this gets the LayoutInflater that’s attached to the current application context. The LayoutInflater is then used to instantiate the layout xml file so that we have a View object that, in line 4, we can attach to the ListView! There is also a method ListView.addFooterView() – you use this in exactly the same way as ListView.addHeaderView().

The full ListActivity class is shown below, it also puts some items in the list.

ListWithHeader.java

package samcoles.listwithheader;

import android.app.ListActivity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;

public class ListWithHeader extends ListActivity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.list_main);

        //add header to list
        ListView lv = getListView();
        LayoutInflater inflater = getLayoutInflater();
        View header = inflater.inflate(R.layout.list_header, (ViewGroup) findViewById(R.id.header_layout_root));
        lv.addHeaderView(header, null, false);

        //add some list items
        String listItems[] = {"List Item One", "List Item Two", "List Item Three", "List Item Four", "List Item Five"};
        lv.setAdapter(new ArrayAdapter(this, android.R.layout.simple_list_item_1, listItems));
    }
}

And here’s a look at that in the emulator:

ListWithHeader

ListWithHeader

 

Noisy Neighbour Icon

Android App: ‘Noisy Neighbour’

0

Since I bought my Android phone last year I have been playing about with the Android SDK. I have worked through some App tutorials and also made a number of little demos using AndEngine.

A couple of weekends’ ago I decided to produce and publish a complete application for the market and ended up building a logging tool to record late night disturbances to your sleep.

You can download ‘Noisy Neighbour’ from the market here.

 

Noisy Neighbour Main Screen

Activity for logging disturbance

Noisy Neighbour Custom Toast

Toast notification after logging a disturbance

Frozen Yoghurt

Root and Upgrade your HTC Desire to Stock Froyo

1

Doesn’t look like HTC will be upgrading your relatively new HTC Desire to Android 2.2 Froyo any time soon. But fortunately there are a number of stable ROMs out there that are quite safe to install. I found a number of the tutorials and posts of advice that are out there were often incomplete, so this is my guide to how I went about getting Froyo on my phone.

  1. Firstly, you will need an unlocked phone before you start. You may need to contact your operator to get the code and they are entitled to charge you an admin fee for this, I think it’s somewhere around £10 for the privilege. Fortunately I had an unlocked stock HTC phone to start with.
  2. Push the menu button on your phone, go to Settings > Applications > Development and make sure the box is checked to allow “USB debugging.”
  3. Here, I formatted the SD card to get rid of all the junk. This can be found in Settings > SD Card & Phone Storage Settings, first you’ll need to tap ‘Unmount SD card’ and then ‘Format SD card.’
  4. Plug your phone into your computer, change it to disk drive mode. You will need to copy across two zip files (complete – do not extract them) into the root of your SD card. The first is the radio image and the second is your choice of custom ROM. You can grab the radio image from here and the custom ROM is your choice. I opted for and reccomend, OpenDesire which, so far seems way more stable than the official HTC 2.1 with Sense ever was. I used the latest version, 2.1 and you can download it from the author here.
  5. Download and run unrevoked³ – this will give you root access on your phone, allow you to create a backup as it stands now and to flash your custom ROM. I’ve heard it just works on Mac, on Windows you may need to install an additional driver from the website and on Linux I had to run it in root mode for it to detect the phone – if you don’t know how to do this because you don’t normally use Linux and you’re running a Live CD or something, then you need to Google “sudo” and read what it has to say. This program takes a couple of minutes to flash and will keep you updated on what it’s up to on the screen. After this step your phone should now have root access – if this is all you want so you can run certain apps then leave it here. Once it’s done you’ll see a menu – you can get back to this screen at any time by holding Volume Down as you switch the phone on.
  6. Make a backup! Scroll down on the menu to “Recovery” using the volume buttons and tap the power button. Use the optical track pad from here, go to “nandroid” on the menu and create your backup. After you’ve done this – if you fudge things up, you can simply roll right back to where you started.
  7. “wipe data/factory reset” – I forgot to do this initially, being my point about incomplete guides. Not doing so caused my phone to get stuck in a loop on the boot screen after I’d flashed the new images, a disappointing and mildly unnerving experience.
  8. “install zip from sdcard” – first up you want to flash the radio image, probably called 32.41.00.32U_5.08.00.04.zip if you didn’t change the name.
  9. “install zip from sdcard” – again, but this time you want to flash the OpenDesire ROM.
  10. “reboot system now” – good luck… remember you can roll back to the beginning using your nandroid backup if something went wrong.

Enjoy! : – )

Go to Top