Show me the code! – By Davanum Srinivas

December 27, 2007

Android – Listen to Phone Notifications using android.os.Mailbox

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

Here is a screen shot.

1

Notes


When i was looking at the strace output closely. I noticed a service named android.telephony.PhoneNotifier. It stuck somewhere in my head. A few(?) days later i ran info the android.os.Mailbox class. Another few days later, when poking into the dexdump output of Phone.apk, it all came together. Here’s the result of experimentation. Basically you can add use a mailbox to receive the notifications from the process that controls the phone. It’s an alternative to registering and listening for intents.

We basically create a mailbox and send a message to the PhoneNotifier to send messages to that mailbox

package org.apache.android.ril;

import android.app.ListActivity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Mailbox;
import android.os.Message;
import android.util.Log;
import android.widget.ArrayAdapter;

import java.util.ArrayList;
import java.util.HashMap;

public class RILSandbox extends ListActivity {

    MyHandler handler = new MyHandler();
    Mailbox myMB = Mailbox.createAnonymous(handler);
    ArrayList items = new ArrayList();

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

        registerForNotification(1);
        registerForNotification(2);
        registerForNotification(3);
        registerForNotification(4);
        registerForNotification(5);
        registerForNotification(6);
        registerForNotification(7);
    }

    private void registerForNotification(int type) {
        Message msg = Message.obtain();
        msg.what = type;
        HashMap map = new HashMap();
        map.put("mailbox", myMB);
        msg.setData(map);
        Mailbox.sendToPublished("android.telephony.PhoneNotifier", msg, null);
    }

    public class MyHandler extends Handler implements Mailbox.Receiver {
        public Object onNewMail(Message message, Mailbox.Completion completion) {
            switch (message.what) {
                case 1:
                    items.add("PhoneState: " + message.getData());
                    break;
                case 2:
                    items.add("ServiceState: " + message.getData());
                    break;
                case 3:
                    items.add("SignalStrength - 1: " + message.getData());
                    items.add("SignalStrength - 2: " + message.arg1);
                    break;
                case 4:
                    items.add("DataConnection: " + message.getData());
                    break;
                case 5:
                    items.add("MessageWaitingChanged - 1: " + message.getData());
                    items.add("MessageWaitingChanged - 2: " + message.arg1);
                    break;
                case 6:
                    items.add("CallForwardingChanged - 1: " + message.getData());
                    items.add("CallForwardingChanged - 2: " + message.arg1);
                    break;
                default:
                    items.add("Unknown - 1: " + message.what);
                    items.add("Unknown - 2: " + message.getData());
                    break;
            }
            updateListAdapter();
            return null;
        }
    }

    private void updateListAdapter() {
        setListAdapter(new ArrayAdapter(this,
                android.R.layout.simple_list_item_1, items));
    }
}

Notes



  • When the app starts up, you will see a few messages float by

  • Try “gsm call +223424” after telnet-ing to 5554 to see additional notifications.

Download Source and APK from here – RILSandbox.zip

December 22, 2007

Android – Send email via GMail (actually via SMTP)

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

Here is a screen shot.

1

The main activity is pretty simple

package org.apache.android.mail;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

public class SendMail extends Activity {
    /**
     * Called with the activity is first created.
     */
    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        setContentView(R.layout.main);
        final Button send = (Button) this.findViewById(R.id.send);
        final EditText userid = (EditText) this.findViewById(R.id.userid);
        final EditText password = (EditText) this.findViewById(R.id.password);
        final EditText from = (EditText) this.findViewById(R.id.from);
        final EditText to = (EditText) this.findViewById(R.id.to);
        final EditText subject = (EditText) this.findViewById(R.id.subject);
        final EditText body = (EditText) this.findViewById(R.id.body);
        send.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view) {
                GMailSender sender = new GMailSender(userid.getText().toString(), password.getText().toString());
                try {
                    sender.sendMail(subject.getText().toString(),
                            body.getText().toString(),
                            from.getText().toString(),
                            to.getText().toString());
                } catch (Exception e) {
                    Log.e("SendMail", e.getMessage(), e);
                }
            }
        });
    }
}

The GMail Sender code is from here

package org.apache.android.mail;

import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.mail.Message;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.Security;
import java.util.Properties;

public class GMailSender extends javax.mail.Authenticator {
    private String mailhost = "smtp.gmail.com";
    private String user;
    private String password;
    private Session session;

    static {
        Security.addProvider(new org.apache.harmony.xnet.provider.jsse.JSSEProvider());
    }

    public GMailSender(String user, String password) {
        this.user = user;
        this.password = password;

        Properties props = new Properties();
        props.setProperty("mail.transport.protocol", "smtp");
        props.setProperty("mail.host", mailhost);
        props.put("mail.smtp.auth", "true");
        props.put("mail.smtp.port", "465");
        props.put("mail.smtp.socketFactory.port", "465");
        props.put("mail.smtp.socketFactory.class",
                "javax.net.ssl.SSLSocketFactory");
        props.put("mail.smtp.socketFactory.fallback", "false");
        props.setProperty("mail.smtp.quitwait", "false");

        session = Session.getDefaultInstance(props, this);
    }

    protected PasswordAuthentication getPasswordAuthentication() {
        return new PasswordAuthentication(user, password);
    }

    public synchronized void sendMail(String subject, String body, String sender, String recipients) throws Exception {
        MimeMessage message = new MimeMessage(session);
        DataHandler handler = new DataHandler(new ByteArrayDataSource(body.getBytes(), "text/plain"));
        message.setSender(new InternetAddress(sender));
        message.setSubject(subject);
        message.setDataHandler(handler);
        if (recipients.indexOf(',') > 0)
            message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(recipients));
        else
            message.setRecipient(Message.RecipientType.TO, new InternetAddress(recipients));
        Transport.send(message);
    }

    public class ByteArrayDataSource implements DataSource {
        private byte[] data;
        private String type;

        public ByteArrayDataSource(byte[] data, String type) {
            super();
            this.data = data;
            this.type = type;
        }

        public ByteArrayDataSource(byte[] data) {
            super();
            this.data = data;
        }

        public void setType(String type) {
            this.type = type;
        }

        public String getContentType() {
            if (type == null)
                return "application/octet-stream";
            else
                return type;
        }

        public InputStream getInputStream() throws IOException {
            return new ByteArrayInputStream(data);
        }

        public String getName() {
            return "ByteArrayDataSource";
        }

        public OutputStream getOutputStream() throws IOException {
            throw new IOException("Not Supported");
        }
    }
}

Notes



  • We use activation-1.1.jar and mail-1.4.jar from SUN

  • Picked up a few classes in java.awt.datatransfer package from Apache Harmony SVN (and stripped them down)

  • Picked up the ByteArrayDataSource class from Apache Axis

  • build.xml adds the 2 jars and the additional harmony/axis classes into the classes.dex as well

Download Source and APK from here – SendMail.zip

December 19, 2007

Android – Support for DRM?

Filed under: Uncategorized — Davanum Srinivas @ 4:26 pm

Looks like there’s some support in Android SDK for OMA DRM.

android.drm.mobile1.DrmConstraintInfo
android.drm.mobile1.DrmException
android.drm.mobile1.DrmRawContent
android.drm.mobile1.DrmRights
android.drm.mobile1.DrmRightsManager

There’s a matching shared object as well named libdrm1_jni.so as well in /system/lib. I cannot find any information on the android site though other than the tantalizing clue here – Environment.getDrmContentDirectory()

Android – Simulate key strokes

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

Here are the before and after screen shot(s).

1

1

We can use IWindowManager’s injectKeyEvent to simulate a series of key strokes

package org.apache.hello;

import android.app.Activity;
import android.os.Bundle;
import android.os.DeadObjectException;
import android.os.ServiceManager;
import android.util.Log;
import android.view.IWindowManager;
import android.view.KeyEvent;
import android.view.View;
import android.widget.Button;

public class HelloApp extends Activity {

    final IWindowManager windowManager = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));

    /**
     * Called with the activity is first created.
     */
    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        this.setContentView(R.layout.main);
        Button fill = (Button) this.findViewById(R.id.fill);
        fill.setOnClickListener(new View.OnClickListener() {

            public void onClick(View view) {
                Thread t = new Thread(new Runnable() {
                    public void run() {
                        try {
                            sendKeySync(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_A));
                            sendKeySync(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_A));
                            sendKeySync(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_N));
                            sendKeySync(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_N));
                            sendKeySync(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_D));
                            sendKeySync(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_D));
                            sendKeySync(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_R));
                            sendKeySync(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_R));
                            sendKeySync(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_O));
                            sendKeySync(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_O));
                            sendKeySync(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_I));
                            sendKeySync(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_I));
                            sendKeySync(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_D));
                            sendKeySync(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_D));
                        } catch (Exception e) {
                            Log.e("HelloApp", e.getMessage(), e);
                        }
                    }
                });
                t.start();
            }
        });
    }

    public void sendKeySync(KeyEvent event) throws DeadObjectException {
        windowManager.injectKeyEvent(event.isDown(), event.getKeyCode(), event.getRepeatCount(), event.getDownTime(), event.getEventTime(), true);
    }
}

Notes


Download Source and APK from here – SimulateKeyStrokes.zip

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

« Newer PostsOlder Posts »

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

Follow

Get every new post delivered to your Inbox.

Join 136 other followers