Friday, February 29, 2008

IntentReceiver only application

IntentReceiver only application

Google Docs: This document is published at http://docs.google.com/Doc?id=ddwc44gs_27dwrnrwrk
WARNING: Blogspot engine change the link, so you have to cut and paste.

If you want to react in some way to one or various Intents and you don't need an Activity you can have an IntentReceiver only application. You class must extend IntentReceiver and you have to override onReceiveIntent method.

This has been asked many time in android groups, but there was no clear answer and ApiDemos doesn't show an example of this either. So I hope this helps and saves you some time.

Create AndroidSampleIntentReceiver project

Create AndroidSampleIntentReceiver project as usual.

You can use Dummy as the Activity and Application name. We will remove them shortly.

Delete Dummy.java

Go to the project and delete Dummy.java right clicking on it and selecting Delete from menu.

Create SampleIntentReceiver class

Right clicking on the com.codtech.android.training.sampleintentreceiver or whatever you've selected for your package, create a new Java class


and edit its content to have

/**
* Copyright © 2008 Diego Torres Milano <dtmilano at gmail dot com>
*/

package com.codtech.android.training.intentreceiver;

import android.content.Context;
import android.content.Intent;
import android.content.IntentReceiver;
import android.util.Log;
import android.widget.Toast;

/**
* @author diego
*
*/

public class SampleIntentReceiver extends IntentReceiver {
private static final String TAG = "SampleIntentReceiver";

/*
* (non-Javadoc)
*
* @see android.content.IntentReceiver#onReceiveIntent(android.content.Context,
* android.content.Intent)
*/

@Override
public void onReceiveIntent(Context context, Intent intent) {
String msg = "SampleIntentReceiver:nonReceiveIntent(context="
+ context.getPackageName()
+ ", intent=[" + intent.getAction() + ", " + intent.getType()
+ ", " + intent.getData() + "])";
Log.d(TAG, msg);
Toast.makeText(context, msg, Toast.LENGTH_LONG).show();
}

}

Modify AndroidManifest.xml

Refactoring the code doesn't change the AndroidManifest.xml, perhaps a deficiency of the Eclipse ADT plugin, so we need to manually edit it. Our intention is to have an application consisting only in an IntentReceiver, with no Activity and this is precisely what we need to remove from this file.

Use the XML view in the editor.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.codtech.android.training.sampleintentreceiver">

<application android:icon="@drawable/icon">
<receiver android:name=".SampleIntentReceiver">
<intent-filter>
<action android:name="com.codtech.android.training.intent.SAMPLE_ACTION"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.GET_CONTENT"/>
<data android:mimeType="image/*"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</receiver>
</application>
</manifest>

We have just added some sample intent-filters, you can add the ones you are interested in.

Install the application

Install you application APK using

 $ adb install AndroidSampleIntentReceiver/bin/AndroidSampleIntentReceiver.apk

Once the application is installed, there's no need to run it. Android will be responsible to run it and invoke onReceiveIntent.

Broadcast an Intent

From your application code, that is another application you want it to broadcast some Intents that will be “trapped” by our SampleIntentReceiver. For example

   Intent intent = new Intent("com.codtech.android.training.intent.SAMPLE_ACTION");
// do something
broadcastIntent(intent, null);

and if everything went well


Thursday, February 28, 2008

Android: Contact photos


Android: Contact photos

You may wonder how you can add photos to your contacts in Android SDK M5. There are at least two very different ways:

  • the correct way
  • the quick and dirty hack way

There's no need to say that the correct way, using Intents didn't work at first, and even we are in an “Open Source” platform, we don't have the sources to check how the Contacts application is shaping its intent to edit the contact's photo.

I've been trying to discover this intent, but no luck yet. More on this later.

So we are destined to the quick and dirty hack.

Contacts database

It's no news that contacts, by default, are stored in a sqlite3 database. I'm putting some emphasis in this because one of the most relevant features of the Android platform is the “All applications are equal” model. So, strictly speaking, Contacts application may have been replaced. However, we will restrict this to the Android default Contacts application, including its ContentProvider. To turn our quest easier, sqlite3 command is provided in the emulator image.

Get a shell to your running emulator using

 $ adb shell

once in the shell

 # sqlite3 /data/data/com.google.android.providers.contacts/databases/contacts.db

There are some tables in this database. We are interested in the people table. If we obtain the schema

CREATE TABLE people (
_id INTEGER PRIMARY KEY,
_sync_account TEXT,
_sync_id TEXT,
_sync_time TEXT,
_sync_version TEXT,
_sync_local_id INTEGER,
_sync_dirty INTEGER,
_sync_mark INTEGER,
name TEXT NOT NULL,
notes TEXT,
photo TEXT,
company TEXT,
title TEXT,
times_contacted INTEGER NOT NULL DEFAULT 0,
last_time_contacted INTEGER,
starred INTEGER NOT NULL DEFAULT 0,
preferred_phone INTEGER REFERENCES phones(_id),
preferred_email INTEGER REFERENCES contact_methods(_id)
);

Obviously, the photo holds the reference to the contact's photo. _id is the unique id of the cont

act.

Photos

We have to store the photos in the filesystem. Let's create a directory to store them.

 # mkdir /data/data/com.google.android.providers.contacts/photos

The push some photos using

 $ adb push <local> <remote>

You can use whatever name you like, but it will be easier if you use the contact unique id to name the photo. We have seen the _id column in the schema before. If you want to verify the ids

 # sqlite3 /data/data/com.google.android.providers.contacts/databases/contacts.db 'select _id,name from people;'

will show something like this

1|Donald Duck
2|Mickey Mouse
3|Pluto
4|Minnie Mouse
5|X


thus, our photos directory should look like this after we transfer the images

-rw-rw-rw-    1 0        0            4625 Feb 27 16:05 1.png
-rw-rw-rw- 1 0 0 4715 Feb 27 16:05 2.png
-rw-rw-rw- 1 0 0 4873 Feb 27 16:05 3.png
-rw-rw-rw- 1 0 0 3085 Feb 27 16:05 4.png

Update the people table

Using sqlite3

# sqlite3 /data/data/com.google.android.providers.contacts/databases/contacts.db
sqlite> UPDATE people SET photo = '/data/data/com.google.android.providers.contacts/photos/' || _id || '.png';

Conclusion

If everything went well, you are now seeing something similar to the previous screenshot. Definitely it's not the way to go, but if you want to provide some photos of your contacts in a quick and dirty way you can do it.

You may say “But wait, what is the correct way ?”

If you touch (or click) the photo while editing a contact you will receive this Unsupported action.

I've tried to receive this Intent to no avail using this intent filter

   <intent-filter>
<action android:name="android.intent.action.GET_CONTENT"/>
<data android:mimeType="image/*"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>

but for some reason, it doesn't match. Do you have an idea ? We would like to know.

Thursday, February 14, 2008

New Android UI


Recently released Android SDK M5 changes the UI almost completely, as well as many aspect of the API that brake application code.
This is understandable as the SDK is under development and these are pre-releases.
Personally, I think that the UI will be heavily changed in next installment of the SDK preview, so it's better if you don't run changing your Android Development Challenge application because perhaps there's another big change before the deadline.
I'm just speculating.

Look at this example. If the API Demos should also be considered as a kind of informal style guide the use of the screen real estate is alarming.
Showing only four options covering the entire screen seems too much.
From the usability point of view there's also some problems. Not showing the scrollbar, how do the users guess that there are some hidden options ?

Friday, February 08, 2008

Android Emulator Speed

Some posts in Android forums have risen the question: how fast is the emulator compared with a real device ?
Honestly, I don't know. Because if you believe that there's no real devices to test out there, not even at MIT, nobody should know.
But we can investigate how the emulator is configured and how fast its CPU is.

Here is the emulator CPU configuration
# cat /proc/cpuinfo
Processor : ARM926EJ-S rev 5 (v5l)
BogoMIPS : 444.00
Features : swp half thumb fastmult vfp edsp java
CPU implementer : 0x41
CPU architecture: 5TEJ
CPU variant : 0x0
CPU part : 0x926
CPU revision : 5
Cache type : write-through
Cache clean : not required
Cache lockdown : not supported
Cache format : Harvard
I size : 4096
I assoc : 4
I line length : 32
I sets : 32
D size : 65536
D assoc : 4
D line length : 32
D sets : 512

Hardware : Goldfish
Revision : 0000
Serial : 0000000000000000

So far, so good. The emulated ARM926EJ-S rev 5 (v5l) is running at 444 bogomips.
What's a bogomip you may wonder. Well according to the Unix Guide, BogoMips is a combination of Bogus and Mips. MIPS stands for (depending on who you ask) Millions of Instructions per Second, or Meaningless Indication of Processor Speed.

For a meaningful comparison, my laptop having Intel(R) Core(TM)2 CPU T5600 @ 1.83GHz, two cores, gives a total of 7319.

If you are running Linux and intrested in obtaining this in your box, just run

$ awk '/bogomips/ {b+=$3} END {print b}' /proc/cpuinfo

Tuesday, February 05, 2008

Undroid

If NetBeans is the IDE of your preference you should take a look at Undroid, a plugin to enable Google’s Android SDK development.
I've installed it without a problem but seems that debugging support is missing in this first release.
I will give it a try and comment the experience in another post.