Show me the code! – By Davanum Srinivas

December 4, 2009

Android – Video/Music player sample (Take #2)

Filed under: Uncategorized — Davanum Srinivas @ 12:55 am

NOTE: Since many folks were looking for it…Here’s the updated version of code originally posted here

Here is a screen shot.

x

Notes



  • You can specify a directory path or a remote URL in the edit box

  • Choose any 3gp file from http://daily3gp.com/ to view videos

  • The 4 buttons are for play, pause, reset and stop

  • When you specify a http or https url, we save the url contents to hard disk first and then play it

  • The icons are from here

Here’s the code

/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.android.media;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.webkit.URLUtil;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.Toast;
import android.widget.VideoView;

public class VideoViewDemo extends Activity {
	private static final String TAG = "VideoViewDemo";

	private VideoView mVideoView;
	private EditText mPath;
	private ImageButton mPlay;
	private ImageButton mPause;
	private ImageButton mReset;
	private ImageButton mStop;
	private String current;

	@Override
	public void onCreate(Bundle icicle) {
		super.onCreate(icicle);
		setContentView(R.layout.main);
		mVideoView = (VideoView) findViewById(R.id.surface_view);

		mPath = (EditText) findViewById(R.id.path);
		mPath.setText("http://daily3gp.com/vids/747.3gp");

		mPlay = (ImageButton) findViewById(R.id.play);
		mPause = (ImageButton) findViewById(R.id.pause);
		mReset = (ImageButton) findViewById(R.id.reset);
		mStop = (ImageButton) findViewById(R.id.stop);

		mPlay.setOnClickListener(new OnClickListener() {
			public void onClick(View view) {
				playVideo();
			}
		});
		mPause.setOnClickListener(new OnClickListener() {
			public void onClick(View view) {
				if (mVideoView != null) {
					mVideoView.pause();
				}
			}
		});
		mReset.setOnClickListener(new OnClickListener() {
			public void onClick(View view) {
				if (mVideoView != null) {
					mVideoView.seekTo(0);
				}
			}
		});
		mStop.setOnClickListener(new OnClickListener() {
			public void onClick(View view) {
				if (mVideoView != null) {
					current = null;
					mVideoView.stopPlayback();
				}
			}
		});
		runOnUiThread(new Runnable(){
			public void run() {
				playVideo();
				
			}
			
		});
	}

	private void playVideo() {
		try {
			final String path = mPath.getText().toString();
			Log.v(TAG, "path: " + path);
			if (path == null || path.length() == 0) {
				Toast.makeText(VideoViewDemo.this, "File URL/path is empty",
						Toast.LENGTH_LONG).show();

			} else {
				// If the path has not changed, just start the media player
				if (path.equals(current) && mVideoView != null) {
					mVideoView.start();
					mVideoView.requestFocus();
					return;
				}
				current = path;
				mVideoView.setVideoPath(getDataSource(path));
				mVideoView.start();
				mVideoView.requestFocus();

			}
		} catch (Exception e) {
			Log.e(TAG, "error: " + e.getMessage(), e);
			if (mVideoView != null) {
				mVideoView.stopPlayback();
			}
		}
	}

	private String getDataSource(String path) throws IOException {
		if (!URLUtil.isNetworkUrl(path)) {
			return path;
		} else {
			URL url = new URL(path);
			URLConnection cn = url.openConnection();
			cn.connect();
			InputStream stream = cn.getInputStream();
			if (stream == null)
				throw new RuntimeException("stream is null");
			File temp = File.createTempFile("mediaplayertmp", "dat");
			temp.deleteOnExit();
			String tempPath = temp.getAbsolutePath();
			FileOutputStream out = new FileOutputStream(temp);
			byte buf[] = new byte[128];
			do {
				int numread = stream.read(buf);
				if (numread <= 0)
					break;
				out.write(buf, 0, numread);
			} while (true);
			try {
				stream.close();
			} catch (IOException ex) {
				Log.e(TAG, "error: " + ex.getMessage(), ex);
			}
			return tempPath;
		}
	}
}

Download Source and APK from here – VideoView.zip

December 29, 2008

Updated XMPP Client for Android

Filed under: Uncategorized — Davanum Srinivas @ 12:09 am

Updated the sources to latest android version – Android 1.0 SDK, Release 2

Original article:
https://davanum.wordpress.com/2007/12/31/android-just-use-smack-api-for-xmpp/

Updated screen shots:
1
2

Download Source and APK from here – XMPPClient-2.zip

October 23, 2008

[android] Building and running Android from source

Filed under: Uncategorized — Davanum Srinivas @ 9:01 am
  • Use the repo script to pull down the source as explained in
  • Make sure you install ncurses headers using “sudo apt-get install ncurses-dev”
  • run make from the root directory
  • run the emulator using “out/host/linux-x86/bin/emulator -system out/target/product/generic/ -kernel prebuilt/android-arm/kernel/kernel-qemu”

PS: Many thanks to massiveRobot on #android IRC channel for the tip for running the emulator.

October 21, 2008

Android is *finally* open

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

http://source.android.com/

May 6, 2008

JavaFX on Android

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

Just saw Rich Green demo JavaFX application on Android Emulator. Looked like a native app, not browser based. Anyone know more details?

December 31, 2007

Android – Just use Smack API for XMPP

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

OUTDATED SAMPLE – Updated code is here:


https://davanum.wordpress.com/2008/12/29/updated-xmpp-client-for-android/

Using Smack XMPP API from Android

Once you get tired of the limitations of android’s built-in IMProvider and the corresponding API – IXmppSession and IXmppService, try the sample below. Inside the source/binary zip (bottom of this article) you will find a smack.jar that works with android. To build the jar yourself, You can download the Smack 3.0.4 sources from here and apply the patch here.

Here is a screen shot of the XMPP Settings Dialog.

1

Notes



  • For GTalk, use “gtalk.google.com” as host with port 5222. The service name is “gmail.com”

  • Don’t add “@gmail.com” in the user name, just the id will do

Here’s the code for the settings dialog

package org.apache.android.xmpp;

import android.app.Dialog;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.Presence;

/**
 * Gather the xmpp settings and create an XMPPConnection
 */
public class SettingsDialog extends Dialog implements android.view.View.OnClickListener {
    private XMPPClient xmppClient;

    public SettingsDialog(XMPPClient xmppClient) {
        super(xmppClient);
        this.xmppClient = xmppClient;
    }

    protected void onStart() {
        super.onStart();
        setContentView(R.layout.settings);
        getWindow().setFlags(4, 4);
        setTitle("XMPP Settings");
        Button ok = (Button) findViewById(R.id.ok);
        ok.setOnClickListener(this);
    }

    public void onClick(View v) {
        String host = getText(R.id.host);
        String port = getText(R.id.port);
        String service = getText(R.id.service);
        String username = getText(R.id.userid);
        String password = getText(R.id.password);

        // Create a connection
        ConnectionConfiguration connConfig =
                new ConnectionConfiguration(host, Integer.parseInt(port), service);
        XMPPConnection connection = new XMPPConnection(connConfig);

        try {
            connection.connect();
            Log.i("XMPPClient", "[SettingsDialog] Connected to " + connection.getHost());
        } catch (XMPPException ex) {
            Log.e("XMPPClient", "[SettingsDialog] Failed to connect to " + connection.getHost());
            xmppClient.setConnection(null);
        }
        try {
            connection.login(username, password);
            Log.i("XMPPClient", "Logged in as " + connection.getUser());

            // Set the status to available
            Presence presence = new Presence(Presence.Type.available);
            connection.sendPacket(presence);
            xmppClient.setConnection(connection);
        } catch (XMPPException ex) {
            Log.e("XMPPClient", "[SettingsDialog] Failed to log in as " + username);
            xmppClient.setConnection(null);
        }
        dismiss();
    }

    private String getText(int id) {
        EditText widget = (EditText) this.findViewById(id);
        return widget.getText().toString();
    }
}

Here is a screen shot of the main window.

1

Notes



  • In the Recipient field, make sure you add the “@gmail.com”, not just the user id

Here’s the code for the main activity

package org.apache.android.xmpp;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
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.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.filter.MessageTypeFilter;
import org.jivesoftware.smack.filter.PacketFilter;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.util.StringUtils;

import java.util.ArrayList;

public class XMPPClient extends Activity {

    private ArrayList<String> messages = new ArrayList();
    private Handler mHandler = new Handler();
    private SettingsDialog mDialog;
    private EditText mRecipient;
    private EditText mSendText;
    private ListView mList;
    private XMPPConnection connection;

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

        mRecipient = (EditText) this.findViewById(R.id.recipient);
        mSendText = (EditText) this.findViewById(R.id.sendText);
        mList = (ListView) this.findViewById(R.id.listMessages);
        setListAdapter();

        // Dialog for getting the xmpp settings
        mDialog = new SettingsDialog(this);

        // Set a listener to show the settings dialog
        Button setup = (Button) this.findViewById(R.id.setup);
        setup.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view) {
                mHandler.post(new Runnable() {
                    public void run() {
                        mDialog.show();
                    }
                });
            }
        });

        // Set a listener to send a chat text message
        Button send = (Button) this.findViewById(R.id.send);
        send.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view) {
                String to = mRecipient.getText().toString();
                String text = mSendText.getText().toString();

                Log.i("XMPPClient", "Sending text [" + text + "] to [" + to + "]");
                Message msg = new Message(to, Message.Type.chat);
                msg.setBody(text);
                connection.sendPacket(msg);
                messages.add(connection.getUser() + ":");
                messages.add(text);
                setListAdapter();
            }
        });
    }

    /**
     * Called by Settings dialog when a connection is establised with the XMPP server
     *
     * @param connection
     */
    public void setConnection
            (XMPPConnection
                    connection) {
        this.connection = connection;
        if (connection != null) {
            // Add a packet listener to get messages sent to us
            PacketFilter filter = new MessageTypeFilter(Message.Type.chat);
            connection.addPacketListener(new PacketListener() {
                public void processPacket(Packet packet) {
                    Message message = (Message) packet;
                    if (message.getBody() != null) {
                        String fromName = StringUtils.parseBareAddress(message.getFrom());
                        Log.i("XMPPClient", "Got text [" + message.getBody() + "] from [" + fromName + "]");
                        messages.add(fromName + ":");
                        messages.add(message.getBody());
                        // Add the incoming message to the list view
                        mHandler.post(new Runnable() {
                            public void run() {
                                setListAdapter();
                            }
                        });
                    }
                }
            }, filter);
        }
    }

    private void setListAdapter
            () {
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
                R.layout.multi_line_list_item,
                messages);
        mList.setAdapter(adapter);
    }
}

Download Source and APK from here – XMPPClient.zip

December 29, 2007

Android – Video/Music player sample (from local disk as well as remote URL’s)

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

Dec-04-2009 : This post is outdated. Please look here for updated code

Here is a screen shot.

1

Notes



  • You can specify a directory path or a remote URL in the edit box

  • You can specify just an mp3 file to play music only

  • Choose any 3gp file from http://daily3gp.com/ to view videos

  • The 4 buttons are for play, pause, reset and stop

  • When you specify a http or https url, we save the url contents to hard disk first and then play it

  • All the leg work was done by dahui. Many thanks!!

  • The icons are from here

  • MediaPlayer does not yet support any remote url’s or MPEG4 video AFAICT

Here’s the code

package org.apache.android;

import android.app.Activity;
import android.graphics.PixelFormat;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnBufferingUpdateListener;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.webkit.URLUtil;
import android.widget.EditText;
import android.widget.ImageButton;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;

public class VideoPlayer extends Activity implements OnErrorListener,
        OnBufferingUpdateListener, OnCompletionListener,
        MediaPlayer.OnPreparedListener, SurfaceHolder.Callback {
    private static final String TAG = "VideoPlayer";

    private MediaPlayer mp;
    private SurfaceView mPreview;
    private EditText mPath;
    private SurfaceHolder holder;
    private ImageButton mPlay;
    private ImageButton mPause;
    private ImageButton mReset;
    private ImageButton mStop;
    private String current;

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

        setContentView(R.layout.main);

        // Set up the play/pause/reset/stop buttons
        mPreview = (SurfaceView) findViewById(R.id.surface);
        mPath = (EditText) findViewById(R.id.path);
        mPlay = (ImageButton) findViewById(R.id.play);
        mPause = (ImageButton) findViewById(R.id.pause);
        mReset = (ImageButton) findViewById(R.id.reset);
        mStop = (ImageButton) findViewById(R.id.stop);

        mPlay.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view) {
                playVideo();
            }
        });
        mPause.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view) {
                if (mp != null) {
                    mp.pause();
                }
            }
        });
        mReset.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view) {
                if (mp != null) {
                    mp.seekTo(0);
                }
            }
        });
        mStop.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view) {
                if (mp != null) {
                    mp.stop();
                    mp.release();
                }
            }
        });

        // Set the transparency
        getWindow().setFormat(PixelFormat.TRANSPARENT);

        // Set a size for the video screen
        holder = mPreview.getHolder();
        holder.setCallback(this);
        holder.setFixedSize(400, 300);
    }

    private void playVideo() {
        try {
            final String path = mPath.getText().toString();
            Log.v(TAG, "path: " + path);

            // If the path has not changed, just start the media player
            if (path.equals(current) && mp != null) {
                mp.start();
                return;
            }
            current = path;

            // Create a new media player and set the listeners
            mp = new MediaPlayer();
            mp.setOnErrorListener(this);
            mp.setOnBufferingUpdateListener(this);
            mp.setOnCompletionListener(this);
            mp.setOnPreparedListener(this);
            mp.setAudioStreamType(2);

            // Set the surface for the video output
            mp.setDisplay(mPreview.getHolder().getSurface());

            // Set the data source in another thread
            // which actually downloads the mp3 or videos
            // to a temporary location
            Runnable r = new Runnable() {
                public void run() {
                    try {
                        setDataSource(path);
                    } catch (IOException e) {
                        Log.e(TAG, e.getMessage(), e);
                    }
                    mp.prepare();
                    Log.v(TAG, "Duration:  ===>" + mp.getDuration());
                    mp.start();
                }
            };
            new Thread(r).start();
        } catch (Exception e) {
            Log.e(TAG, "error: " + e.getMessage(), e);
            if (mp != null) {
                mp.stop();
                mp.release();
            }
        }
    }

    /**
     * If the user has specified a local url, then we download the
     * url stream to a temporary location and then call the setDataSource
     * for that local file
     *
     * @param path
     * @throws IOException
     */
    private void setDataSource(String path) throws IOException {
        if (!URLUtil.isNetworkUrl(path)) {
            mp.setDataSource(path);
        } else {
            URL url = new URL(path);
            URLConnection cn = url.openConnection();
            cn.connect();
            InputStream stream = cn.getInputStream();
            if (stream == null)
                throw new RuntimeException("stream is null");
            File temp = File.createTempFile("mediaplayertmp", "dat");
            String tempPath = temp.getAbsolutePath();
            FileOutputStream out = new FileOutputStream(temp);
            byte buf[] = new byte[128];
            do {
                int numread = stream.read(buf);
                if (numread <= 0)
                    break;
                out.write(buf, 0, numread);
            } while (true);
            mp.setDataSource(tempPath);
            try {
                stream.close();
            }
            catch (IOException ex) {
                Log.e(TAG, "error: " + ex.getMessage(), ex);
            }
        }
    }

    public void onError(MediaPlayer mediaPlayer, int what, int extra) {
        Log.e(TAG, "onError--->   what:" + what + "    extra:" + extra);
        if (mediaPlayer != null) {
            mediaPlayer.stop();
            mediaPlayer.release();
        }
    }

    public void onBufferingUpdate(MediaPlayer arg0, int percent) {
        Log.d(TAG, "onBufferingUpdate called --->   percent:" + percent);
    }

    public void onCompletion(MediaPlayer arg0) {
        Log.d(TAG, "onCompletion called");
    }

    public void onPrepared(MediaPlayer mediaplayer) {
        Log.d(TAG, "onPrepared called");
    }

    public boolean surfaceCreated(SurfaceHolder surfaceholder) {
        Log.d(TAG, "surfaceCreated called");
        return true;
    }

    public void surfaceChanged(SurfaceHolder surfaceholder, int i, int j, int k) {
        Log.d(TAG, "surfaceChanged called");
    }

    public void surfaceDestroyed(SurfaceHolder surfaceholder) {
        Log.d(TAG, "surfaceDestroyed called");
    }
}

Download Source and APK from here – VideoPlayer.zip

December 27, 2007

Android – using android.os.Mailbox for asychronous communication

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

Here is a screen shot.

1

Here’s how you set up a new Mailbox

// Create a mailbox and publish it.
Mailbox.createAndPublish("MyMailbox", new MyReceiver());

MyReceiver snippet and Notes



  • when we get a message with msg.what == TEST1, we add another entry in the hash map and send it back

  • when we get a message with msg.what == TEST2, we throw an exception

  • for TEST3 and TEST4, we just send the message after a delay, just to illustrate that we can send the response asynchronously

    /**
     * Receiver for the Mailbox
     */
    private class MyReceiver extends Handler implements Mailbox.Receiver {
        public Object onNewMail(final Message msg, final Mailbox.Completion completion) {
            switch (msg.what) {
                case TEST1:
                    HashMap map = msg.getData();
                    map.put("hello", "world");
                    return map;

                case TEST2:
                    throw new RuntimeException();

                case TEST3:
                    completion.setAutoComplete(false);
                    // Send response after 5 seconds.
                    postDelayed(new Runnable() {
                        public void run() {
                            HashMap map = msg.getData();
                            map.put("hello", "world");
                            completion.complete(map);
                        }
                    }, 5000L);
                    return null;

                case TEST4:
                    completion.setAutoComplete(false);
                    // Send exception after 5 seconds.
                    postDelayed(new Runnable() {
                        public void run() {
                            completion.completeWithException(new RuntimeException());
                        }
                    }, 5000L);
                    return null;

                default:
                    throw new RuntimeException("Got unknown message " + msg);
            }
        }
    }

Sending messages to the mailbox

Not too complicated..

// Setup request/response data structures
Message request = handler.obtainMessage(TEST4);
HashMap map = new HashMap();
map.put("test.name", "test4");
request.setData(map);
Message response = handler.obtainMessage(RESPONSE);

// Send the request to the mailbox
Mailbox.sendToPublished("MyMailbox", request, response);

Receiving the response back from the mailbox

Just another Handler..

    /**
     * Handler updates the text area with the response or exception
     */
    private class MyUIReceiver extends Handler {
        public void handleMessage(android.os.Message message) {
            switch (message.what) {
                case RESPONSE:
                    TextView text = (TextView) MyMailbox.this.findViewById(R.id.text);
                    AsyncResult result = (AsyncResult) message.obj;
                    if (result.exception != null) {
                        text.setText(result.exception.toString());
                    } else {
                        text.setText(result.result.toString());
                    }
                    break;
            }
        }
    }

Saving the best for last!!



  • You can send messages from another process not just the same process!

  • Looks like you can stuff any Parcelable object into the hashmap (and don’t have to stick to just AIDL!!)

Download Source and APK from here – Mailbox.zip

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

Older Posts »

Blog at WordPress.com.