Show me the code! – By Davanum Srinivas

December 18, 2007

Android – Task manager primitive prototype

Filed under: Uncategorized — Davanum Srinivas @ 9:27 am

Here’s a screen shot

1

Setup the Android Manifest with the “android.permission.GET_TASKS” permission

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="org.apache.hello">
    <uses-permission id="android.permission.GET_TASKS"/>
    <application>
        <activity class=".HelloApp" android:label="HelloApp">
            <intent-filter>
                <action android:value="android.intent.action.MAIN" />
                <category android:value="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest> 

Code a simple ListActivity

package org.apache.hello;

import android.app.ActivityManagerNative;
import android.app.IActivityManager;
import android.app.ListActivity;
import android.os.Bundle;
import android.os.DeadObjectException;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class HelloApp extends ListActivity {

    final IActivityManager manager = ActivityManagerNative.getDefault();

    /**
     * Called with the activity is first created.
     */
    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);

        updateTaskList();

        this.getListView().setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            public void onItemSelected(AdapterView adapterview, View view, int i, long l) {
                try {
                    manager.moveTaskToFront(i);
                } catch (DeadObjectException e) {
                    Log.e("HelloApp", e.getMessage(), e);
                }
            }

            public void onNothingSelected(AdapterView adapterview) {
            }
        });
    }

    public void onWindowFocusChanged(boolean flag) {
        updateTaskList();
    }

    private void updateTaskList() {
        ArrayList items = new ArrayList();
        try {
            List tasks = manager.getTasks(10, 0, null);
            int i = 1;
            for (Iterator iterator = tasks.iterator(); iterator.hasNext();) {
                IActivityManager.TaskInfo item = (IActivityManager.TaskInfo) iterator.next();
                items.add(new String((i++) + " : " + item.baseActivity.getPackageName()));
            }
        } catch (DeadObjectException e) {
            Log.e("HelloApp", e.getMessage(), e);
        }
        setListAdapter(new ArrayAdapter(this,
                android.R.layout.simple_list_item_1, items));
    }
}

Running the sample



  • Install the APK using “adb install HelloApp.apk” as usual

  • Click to open the app and click on any listed application to switch to it
  • Download Source and APK from here – TaskList.zip

December 15, 2007

Android – Listen for incoming SMS messages

Filed under: Uncategorized — Davanum Srinivas @ 10:06 am

Get the latest m3-rc37a version of android

Here’s a screen shot

1

Setup the Android Manifest with the permission and the Intent Receiver

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="org.apache.sms">
    <uses-permission id="android.permission.RECEIVE_SMS" />
    <application>
        <receiver class="SMSApp">
            <intent-filter>
                <action android:value="android.provider.Telephony.SMS_RECEIVED" />
            </intent-filter>
        </receiver>
    </application>
</manifest> 

Code a simple Intent Listener

package org.apache.sms;

import android.app.NotificationManager;
import android.content.Context;
import android.content.Intent;
import android.content.IntentReceiver;
import android.os.Bundle;
import android.provider.Telephony;
import android.util.Log;
import android.telephony.gsm.SmsMessage;

public class SMSApp extends IntentReceiver {
    private static final String LOG_TAG = "SMSApp";

    /* package */ static final String ACTION =
            "android.provider.Telephony.SMS_RECEIVED";

    public void onReceiveIntent(Context context, Intent intent) {
        if (intent.getAction().equals(ACTION)) {
            StringBuilder buf = new StringBuilder();
            Bundle bundle = intent.getExtras();
            if (bundle != null) {
                SmsMessage[] messages = Telephony.Sms.Intents.getMessagesFromIntent(intent);
                for (int i = 0; i &lt; messages.length; i++) {
                    SmsMessage message = messages[i];
                    buf.append("Received SMS from  ");
                    buf.append(message.getDisplayOriginatingAddress());
                    buf.append(" - ");
                    buf.append(message.getDisplayMessageBody());
                }
            }
            Log.i(LOG_TAG, "[SMSApp] onReceiveIntent: " + buf);
            NotificationManager nm = (NotificationManager) context.getSystemService(
                    Context.NOTIFICATION_SERVICE);

            nm.notifyWithText(123, buf.toString(),
                    NotificationManager.LENGTH_LONG, null);

        }
    }

    private void appendData(StringBuilder buf, String key, String value) {
        buf.append(", ");
        buf.append(key);
        buf.append('=');
        buf.append(value);
    }
}

Running the sample



  • Install the APK using “adb install SMSApp.apk” as usual

  • Open a telnet session to localhost at port 5554 and type “sms send +5085551212 hello” to simulate an sms message
  • Download Source and APK from here – SMSApp.zip

December 14, 2007

Android – Accessing the system services

Filed under: Uncategorized — Davanum Srinivas @ 9:59 am

Here’s a partial listing of the available services on android.

Access the Service Manager and list available services

android.os.IServiceManager sm = android.os.ServiceManagerNative.getDefault();
        try {
            String[] services = sm.listServices();
            for (int i = 0; i < services.length; i++) {
                Log.i("Services", i + " : " + services[i]);
            }
        } catch (DeadObjectException e) {
            Log.i("Services", e.getMessage(), e);
        }

Now we try to dig thru the API to figure out which ones are available to applications. Here’s what i have found so far.

USB

android.os.IUsb usbService = android.os.IUsb.Stub.asInterface(sm.getService("USB"));

javadoc – IUsb

activity

android.app.IActivityManager activityService = android.app.IActivityManager.Stub.asInterface(sm.getService("activity"));

alarm

android.app.IAlarmManager alarmService = android.app.IAlarmManager.Stub.asInterface(sm.getService("alarm"));

content

android.content.IContentService contentService = android.content.IContentService.Stub.asInterface(sm.getService("content"));

location

android.location.ILocationManager locationService = android.location.ILocationManager.Stub.asInterface(sm.getService("location"));

notification

android.app.INotificationManager notificationService = android.app.INotificationManager.Stub.asInterface(sm.getService("notification"));

org.bluez.bluetooth

	org.bluez.IBluetoothService bluetoothService = org.bluez.IBluetoothService.Stub.asInterface(sm.getService("org.bluez.bluetooth_service"));

javadoc – IBluetoothService

package

android.content.IPackageManager packageService = android.content.IPackageManager.Stub.asInterface(sm.getService("package"));

phone

android.telephony.IPhone phoneService = android.telephony.IPhone.Stub.asInterface(sm.getService("phone"));

javadoc – IPhone

power

android.os.IPowerManager powerService = android.os.IPowerManager.Stub.asInterface(sm.getService("power"));

statistics

android.os.IStatisticsService statisticsService = android.os.IStatisticsService.Stub.asInterface(sm.getService("statistics"));

statusbar

android.server.status.IStatusBar statusbarService = android.server.status.IStatusBar.Stub.asInterface(sm.getService("statusbar"));

vibrator

android.os.IVibratorService vibratorService = android.os.IVibratorService.Stub.asInterface(ServiceManager.getService("vibrator"));

volume

android.view.IRingerVolume volumeService = android.view.RingerVolumeNative.asInterface(sm.getService("volume"));

window

android.view.IWindowManager windowService = android.view.IWindowManager.Stub.asInterface(sm.getService("window"));

December 12, 2007

Android – Call/Dial from the adb shell command line

Filed under: Uncategorized — Davanum Srinivas @ 2:43 pm

Check if the “phone” service is up and running

C:\android\DialPhone>adb shell
# service check phone
service check phone
Service phone: found

Dial a specific contact in the contact list

# service call phone 1 s16 "davanum"
service call phone 1 s16 "davanum"
Result: Parcel(NULL)

1

Dial a specific phone #

# service call phone 2 s16 "+15084157509"
service call phone 2 s16 "+15084157509"
Result: Parcel(NULL)

1

Home work – try these and leave me a comment on what it affects in the emulator

# service call phone 8 i32 0
service call phone 8 i32 0
Result: Parcel(NULL)
# service call phone 8 i32 1
service call phone 8 i32 1
Result: Parcel(NULL)

Other options

# service
service
Usage: service [-h|-?]
       service check SERVICE
       service call SERVICE CODE [i32 INT | s16 STR] ...
Options:
   i32: Write the integer INT into the send parcel.
   s16: Write the UTF-16 string STR into the send parcel.

December 11, 2007

Android – How to poke around the sqlite3 databases

Filed under: Uncategorized — Davanum Srinivas @ 10:00 pm

Find and connect to a database

You can find busybox on Benno’s site. If you can find the location of the .db file, you don’t really need busybox. Though i highly recommend it since it has many useful utilities.

C:\android>adb shell
# export PATH=/data/busybox:$PATH
export PATH=/data/busybox:$PATH
# find data -name "*.db" -print
find data -name "*.db" -print
data/data/com.google.android.providers.contacts/databases/contacts.db
data/data/com.google.android.providers.googleapps/databases/accounts.db
data/data/com.google.android.providers.im/databases/im.db
data/data/com.google.android.providers.media/databases/media.db
data/data/com.google.android.providers.telephony/databases/mms.db
data/data/com.google.android.providers.telephony/databases/sms.db
data/data/com.google.android.providers.telephony/databases/telephony.db
data/data/com.google.android.providers.settings/databases/settings.db
data/data/com.google.android.maps/databases/maps.db
# sqlite3 data/data/com.google.android.providers.contacts/databases/contacts.db
sqlite3 data/data/com.google.android.providers.contacts/databases/contacts.db
SQLite version 3.5.0
Enter ".help" for instructions
sqlite>

Find the list of tables and their structure

sqlite> .tables
.tables
_deleted_people  contact_methods  peopleLookup
calls            people           phones
sqlite> .schema people
.schema people
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,preferred_phone INTEGER,preferred_email INTEGER);
CREATE INDEX peopleSyncIdIndex ON people (_sync_id);
CREATE TRIGGER contact_cleanup DELETE ON people BEGIN DELETE FROM peopleLookup WHERE source = old._id;DELETE FROM phones WHERE person = old._id;DELETE FROM contact_methods WHERE person = old._id;UPDATE calls SET person = NULL WHERE person = old._id;END;
CREATE TRIGGER contact_to_deleted DELETE ON people WHEN old._sync_id is not null BEGIN INSERT INTO _deleted_people (_sync_id, _sync_account, _sync_version) VALUES (old._sync_id, old._sync_account, old._sync_version);END;
CREATE TRIGGER peopleLookup_insert AFTER INSERT ON people BEGIN SELECT _TOKENIZE('peopleLookup', new._id, new.name, ' ');END;
CREATE TRIGGER peopleLookup_update UPDATE OF name ON people BEGIN DELETE FROM peopleLookup WHERE source = new._id;SELECT _TOKENIZE('peopleLookup', new._id, new.name, ' ');END;
sqlite> .schema phones
.schema phones
CREATE TABLE phones (_id INTEGER PRIMARY KEY,person INTEGER,type INTEGER,number TEXT,number_key TEXT,label TEXT);
CREATE INDEX phonesIndex1 ON phones (person);
CREATE INDEX phonesIndex2 ON phones (number_key);
CREATE TRIGGER phones_delete DELETE ON phones BEGIN UPDATE people SET _sync_dirty=1 WHERE people._id=old.person;END;
CREATE TRIGGER phones_insert INSERT ON phones BEGIN UPDATE people SET _sync_dirty=1 WHERE people._id=new.person;END;
CREATE TRIGGER phones_update UPDATE ON phones BEGIN UPDATE people SET _sync_dirty=1 WHERE people._id=old.person;END;
CREATE TRIGGER preferred_phone_cleanup DELETE ON phones BEGIN UPDATE people SET preferred_phone = NULL WHERE preferred_phone = old._id; END;

Print some of the information from the tables

sqlite> .header on
.header on
sqlite> .mode column
.mode column
sqlite> select * from phones;
select * from phones;
_id         person      type        number        number_key    label
----------  ----------  ----------  ------------  ------------  ----------
1           1           1           +15085551212  21215558051+
2           1           0           +17815551212  21215551871+
3           1           2           +16175551212  21215557161+
sqlite> select * from people;
select * from people;
_id         _sync_account  _sync_id    _sync_time  _sync_version  _sync_local_id  _sync_dirty  _sync_mark  name              notes       photo       company     title       preferred_phone  preferred_email
----------  -------------  ----------  ----------  -------------  --------------  -----------  ----------  ----------------  ----------  ----------  ----------  ----------  ---------------  ---------------
1                                                                                 1                        Davanum Srinivas                                                  1

Other commands

sqlite> .help
.help
.bail ON|OFF           Stop after hitting an error.  Default OFF
.databases             List names and files of attached databases
.dump ?TABLE? ...      Dump the database in an SQL text format
.echo ON|OFF           Turn command echo on or off
.exit                  Exit this program
.explain ON|OFF        Turn output mode suitable for EXPLAIN on or off.
.header(s) ON|OFF      Turn display of headers on or off
.help                  Show this message
.import FILE TABLE     Import data from FILE into TABLE
.indices TABLE         Show names of all indices on TABLE
.load FILE ?ENTRY?     Load an extension library
.mode MODE ?TABLE?     Set output mode where MODE is one of:
                         csv      Comma-separated values
                         column   Left-aligned columns.  (See .width)
                         html     HTML  code
                         insert   SQL insert statements for TABLE
                         line     One value per line
                         list     Values delimited by .separator string
                         tabs     Tab-separated values
                         tcl      TCL list elements
.nullvalue STRING      Print STRING in place of NULL values
.output FILENAME       Send output to FILENAME
.output stdout         Send output to the screen
.prompt MAIN CONTINUE  Replace the standard prompts
.quit                  Exit this program
.read FILENAME         Execute SQL in FILENAME
.schema ?TABLE?        Show the CREATE statements
.separator STRING      Change separator used by output mode and .import
.show                  Show the current values for various settings
.tables ?PATTERN?      List names of tables matching a LIKE pattern
.timeout MS            Try opening locked tables for MS milliseconds
.width NUM NUM ...     Set column widths for "column" mode

Notes


More info in the original posts from Jason and Luisa.

December 9, 2007

Android – Invoke JNI based methods (Bridging C/C++ and Java)

Filed under: Uncategorized — Davanum Srinivas @ 11:23 pm

Here’s a screen shot

1

Step By Step Instructions below:


Step #1: Compile the project using ant. Some snippets are shown below.

NativeAdd.java class (with Native method)

package org.apache;

import android.util.Log;

public class NativeAdd {
    static {
        try {
            Log.i("JNI", "Trying to load libNativeAdd.so");
            System.loadLibrary("NativeAdd");
        }
        catch (UnsatisfiedLinkError ule) {
            Log.e("JNI", "WARNING: Could not load libNativeAdd.so");
        }
    }

    public static native long add(long a, long b);
}

Snippet that shows how this class/method is invoked from the main activity

    public void onClick(View view) {
        Log.i(LOG_TAG, "onClick");

        EditText a = (EditText) findViewById(R.id.a);
        EditText b = (EditText) findViewById(R.id.b);
        EditText c = (EditText) findViewById(R.id.c);
        Log.i(LOG_TAG, "calling native method");
        long sum = NativeAdd.add(Long.parseLong(a.getText().toString()),
                Long.parseLong(b.getText().toString()));
        Log.i(LOG_TAG, "back from native method");
        String text = Long.toString(sum);
        c.setText("Native add returns = " + text.subSequence(0, text.length()));
    }

Step #2: Generate header files using java by running the following command.

javah -classpath ../../android.jar;../bin/classes; org.apache.NativeAdd

Here’s how the header file (org_apache_CallNative.h) looks like

/* DO NOT EDIT THIS FILE - it is machine generated */
#include 
/* Header for class org_apache_NativeAdd */

#ifndef _Included_org_apache_NativeAdd
#define _Included_org_apache_NativeAdd
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     org_apache_NativeAdd
 * Method:    add
 * Signature: (JJ)J
 */
JNIEXPORT jlong JNICALL Java_org_apache_NativeAdd_add
  (JNIEnv *, jclass, jlong, jlong);

#ifdef __cplusplus
}
#endif
#endif

Step #3: Code a tiny C file (org_apache_NativeAdd.c) as shown below:

#include "org_apache_NativeAdd.h"

JNIEXPORT jlong JNICALL Java_org_apache_NativeAdd_add
  (JNIEnv *env, jclass c, jlong a, jlong b)
{
    return a + b;
}

Step #4: Please read the following article before you try the next step.
Shared library “Hello World!” for Android

Step #5: Compile and link the org_apache_NativeAdd.c/org_apache_NativeAdd.h into a shared library.

arm-none-linux-gnueabi-gcc  -I/usr/lib/jvm/java-1.5.0-sun/include -I/usr/lib/jvm/java-1.5.0-sun/include/linux  -fpic -c org_apache_NativeAdd.c
arm-none-linux-gnueabi-ld -T armelf_linux_eabi.xsc -shared -o libNativeAdd.so org_apache_NativeAdd.o

NOTE: details on armelf_linux_eabi.xsc are in the Step #4.

Step #6: copy the library to the emulator. Copy the Application as well.
adb push native/libNativeAdd.so /system/lib
adb install bin/CallNative.apk

Step #7: Run the app to try some values. That's it!

Download the sources and Application - CallNative.zip

Android – Reverse GeoCode – find information about a specified lat/long using MapPoint Web Service

Filed under: Uncategorized — Davanum Srinivas @ 2:55 pm

Here’s a sample on how to use Microsoft’s MapPoint SOAP API to get information on a specified latitude/longitude

1

Just enter your Mappoint userid, password, latitude, longitude and press lookup button.

Notes


Here’s the application:

package org.apache.geocode;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import org.apache.commons.httpclient.Credentials;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.auth.AuthPolicy;
import org.apache.commons.httpclient.auth.AuthScope;
import org.apache.commons.httpclient.methods.PostMethod;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.IOException;
import java.util.List;

/**
 * Uses the MapPoint Web Service to get details (of nearby locations/addresses) on a specified lat/long
 */
public class ReverseGeoCoder extends Activity implements View.OnClickListener {

    // UI elements
    private Button mLookup;
    private EditText mUserId;
    private EditText mPassword;
    private EditText mLatitude;
    private EditText mLongitude;

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

        // Gather the troops
        mUserId = (EditText) findViewById(R.id.username);
        mPassword = (EditText) findViewById(R.id.password);
        mLatitude = (EditText) findViewById(R.id.latitude);
        mLongitude = (EditText) findViewById(R.id.longitude);
        mLookup = (Button) findViewById(R.id.lookup);

        // Set up a couple of button listeners
        mLookup.setOnClickListener(this);
    }

    // SOAP Request for the FindServiceSOAP.GetLocationInfo web service
    String soapRequestXML_1 = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
            "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" " +
            "               xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " +
            "               xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">\n" +
            "  <soap:Body>\n" +
            "    <GetLocationInfo xmlns=\"http://s.mappoint.net/mappoint-30/\">\n" +
            "      <location>";
    String soapRequestXML_2 = "      </location>\n" +
            "      <dataSourceName>MapPoint.NA</dataSourceName>\n" +
            "      <options/>\n" +
            "    </GetLocationInfo>\n" +
            "  </soap:Body>\n" +
            "</soap:Envelope>";

    /**
     * When the user clicks on the lookup button we use the MapPoint SOAP API to fetch the
     * information of the specified latitude longitude.
     *
     * @param view
     */
    public void onClick(View view) {

        String user = mUserId.getText().toString();
        String password = mPassword.getText().toString();
        String latitude = mLatitude.getText().toString();
        String longitude = mLongitude.getText().toString();

        // Use our customized Digest Auth scheme as per the following article
        // http://go.mappoint.net/MappointMPAC/default.aspx?main=article.aspx&id=J10002
        AuthPolicy.registerAuthScheme(AuthPolicy.DIGEST, DigestMapPointScheme.class);

        String url = "http://findv3.staging.mappoint.net/Find-30/FindService.asmx";
        HttpClient client = new HttpClient();
        client.setConnectionTimeout(8000);

        Credentials credentials = new UsernamePasswordCredentials(user, password);
        client.getState().setCredentials(AuthScope.ANY, credentials);

        PostMethod postMethod = new PostMethod(url);

        // Construct a SOAP request by hand
        StringBuffer request = new StringBuffer();
        request.append(soapRequestXML_1);
        request.append("<Latitude>").append(latitude).append("</Latitude>");
        request.append("<Longitude>").append(longitude).append("</Longitude>");
        request.append(soapRequestXML_2);
        postMethod.setRequestBody(request.toString());
        postMethod.setRequestHeader("Content-Type",
                "text/xml; charset=utf-8");
        postMethod.setRequestHeader("SOAPAction",
                "\"http://s.mappoint.net/mappoint-30/GetLocationInfo\"");

        int statusCode = 0;
        try {
            statusCode = client.executeMethod(postMethod);
        } catch (IOException e) {
            Log.d("ReverseGeoCoder", e.toString(), e);
        }

        Log.i("ReverseGeoCoder", "statusCode>>>" + statusCode);
        Log.i("ReverseGeoCoder", "statusLine>>>" + postMethod.getStatusLine());

        // Parse the SOAP Response
        MyContentHandler myContentHandler = new MyContentHandler();
        try {
            SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
            parser.parse(postMethod.getResponseBodyAsStream(), myContentHandler);
        } catch (Exception e) {
            Log.d("ReverseGeoCoder", e.toString(), e);
        }

        // Display the response details.
        List list = myContentHandler.getLocations();
        String[] items = new String[list.size()];
        for (int i = 0; i < list.size(); i++) {
            MyContentHandler.MyLocation location = (MyContentHandler.MyLocation) list.get(i);
            Log.i("ReverseGeoCoder", "Location : " + i);
            Log.i("ReverseGeoCoder", "Latitude : " + location.latitude);
            Log.i("ReverseGeoCoder", "Longitude : " + location.longitude);
            Log.i("ReverseGeoCoder", "Description : " + location.description);
            items[i] = location.description + " (geo:" + location.latitude + "," + location.longitude + ")";
        }
        // Show the data in the list view
        ListView listView = (ListView) findViewById(R.id.data);
        listView.setAdapter(new ArrayAdapter<String>(this,
                android.R.layout.simple_list_item_1,
                items));
        postMethod.releaseConnection();
    }
}

Download the sources and Application – ReverseGeoCode.zip

December 5, 2007

Android – Use ATOM/GData API to access the Google Calendar

Filed under: Uncategorized — Davanum Srinivas @ 11:15 pm

Here’s a sample on how to use access Google Calendar from Android


1

Just enter your userid (with @gmail.com), password, select any date and press lookup button.

Here’s the meat of the application:

import com.google.android.gdata.client.AndroidXmlParserFactory;
import com.google.android.gdata.client.JakartaGDataClient;
import com.google.wireless.gdata.calendar.client.CalendarClient;
import com.google.wireless.gdata.calendar.data.EventEntry;
import com.google.wireless.gdata.calendar.data.When;
import com.google.wireless.gdata.calendar.parser.xml.XmlCalendarGDataParserFactory;
import com.google.wireless.gdata.client.QueryParams;
import com.google.wireless.gdata.data.Feed;
import com.google.wireless.gdata.parser.GDataParser;
    /**
     * When the user clicks on the lookup button we use the ATOM/GData API to fetch the
     * details of events for a specific date
     * @param view
     */
    public void onClick(View view) {
        XmlCalendarGDataParserFactory factory = new XmlCalendarGDataParserFactory(new AndroidXmlParserFactory());
        JakartaGDataClient dataClient = new JakartaGDataClient();

        // Generate the URL for a private ATOM feed in google calendar 
        String url = "http://www.google.com/calendar/feeds/" +
                dataClient.encodeUri(mUserId.getText().toString()) + "/private/full";
        QueryParams params = dataClient.createQueryParams();
        String pad1 = (mMonth + 1) < 10 ? "0" : "";
        String pad2 = mDay < 10 ? "0" : "";
        params.setParamValue("start-min", mYear + "-" + pad1 + (mMonth + 1) + "-" + pad2 + mDay + "T00:00:00");
        params.setParamValue("start-max", mYear + "-" + pad1 + (mMonth + 1) + "-" + pad2 + mDay + "T23:59:59");
        url = params.generateQueryUrl(url);
        Log.i("GoogleContacts", "URL :" + url);

        CalendarClient client = new CalendarClient(dataClient, factory, url);
        try {
            Log.i("GoogleContacts", "BaseFeedUrl:" + client.getBaseFeedUrl());

            String user = mUserId.getText().toString();
            String password = mPassword.getText().toString();
            Log.i("GoogleContacts", "userid:" + user);
            Log.i("GoogleContacts", "password:" + password);

            // Get the google token
            String authToken = client.getAuthToken(user, password);
            Log.i("GoogleContacts", "Token:" + authToken);

            // Use the token and access the actual feed.
            java.io.InputStream is = dataClient.getFeedAsStream(url, authToken);
            GDataParser parser = factory.createParser(is);
            Feed feed = parser.init();

            int totalResults = feed.getTotalResults();
            Log.i("GoogleContacts", "Results:" + totalResults);

            // wade thru the entries and pick interesting information
            EventEntry entry = null;
            String[] items = new String[totalResults];
            for (int i = 0; i < totalResults; i++) {
                entry = (EventEntry) parser.readNextEntry(entry);
                Log.i("GoogleContacts", "Entry ID:" + entry.getId());
                Log.i("GoogleContacts", "Entry Title:" + entry.getTitle());
                Log.i("GoogleContacts", "Update Date:" + entry.getUpdateDate());
                When when = entry.getFirstWhen();
                Date time1 = zulu.parse(when.getStartTime());
                Date time2 = zulu.parse(when.getEndTime());
                Log.i("GoogleContacts", "Date/Time: FROM " + zulu2.format(time1) + " TO " + zulu2.format(time2));
                items[i] = zulu2.format(time1) + " - " + zulu2.format(time2) + " : " + entry.getTitle();
            }

            // Display the information in the list view
            ListView listView = (ListView) findViewById(R.id.data);
            listView.setAdapter(new ArrayAdapter(this,
                    android.R.layout.simple_list_item_1,
                    items));
        } catch (Exception e) {
            Log.e("GoogleContacts", e.toString(), e);
        }
    }

Download the sources and Application – GoogleCalendar.zip

December 4, 2007

Command line Java on DalvikVM

Filed under: Uncategorized — Davanum Srinivas @ 11:21 am

Found this very useful when i was trying out the JNI under android (Short Story – Could not get it to work!).

Step #1: Start with a simple java class

package org.apache;

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello World!");
    }
}

Compile the java class

C:\android\CmdLine>javac -d . -g Helloworld.java

Step #2: Package the generated classes into a temporary jar

C:\android\CmdLine>jar -cvf Temp.jar *
added manifest
adding: Hello.java(in = 0) (out= 0)(stored 0%)
adding: HelloWorld.java(in = 149) (out= 122)(deflated 18%)
adding: org/(in = 0) (out= 0)(stored 0%)
adding: org/apache/(in = 0) (out= 0)(stored 0%)
adding: org/apache/HelloWorld.class(in = 556) (out= 344)(deflated 38%)

Step #3: Use the “dx” tool to generate a classes.dex from our temporary jar.

C:\android\CmdLine>dx --dex --output=c:/android/CmdLine/classes.dex c:/android/CmdLine/Temp.jar

Step #4: Use the “aapt” tool to create a new jar suitable for use with dalvikvm

C:\android\CmdLine>aapt add CmdLine.jar classes.dex
 'classes.dex'...

and push it into a known location on the emulator

C:\android\CmdLine>adb push CmdLine.jar /data
30 KB/s (0 bytes in 481.000s)

Step #5: kick the tires of dalvikvm

C:\android\CmdLine>adb shell
# /system/bin/dalvikvm -Xbootclasspath:/system/framework/core.jar -version
/system/bin/dalvikvm -Xbootclasspath:/system/framework/core.jar -version
DalvikVM version 0.2.0
Copyright (C) 2007 Google, Inc.
Blah blah blah LICENSE blah blah.
Dalvik VM init failed (check log file)

Step #6: Run our code

# /system/bin/dalvikvm -Xbootclasspath:/system/framework/core.jar -classpath /data/CmdLine.jar org.apache.HelloWorld
/system/bin/dalvikvm -Xbootclasspath:/system/framework/core.jar -classpath /data/CmdLine.jar org.apache.HelloWorld
Hello World!

Android Quick Tip – 1 liner to make the VM wait for debugger to connect

Filed under: android — Davanum Srinivas @ 6:46 am

Add this line in your code and when you run the application hits this method, it will wait till you connect with a debugger.


android.os.Debug.waitForDebugger();

Which port you ask? run the “ddms” utility and see for yourself which port your application is waiting on.

« Newer PostsOlder Posts »

The Shocking Blue Green Theme. Blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.

Join 131 other followers