Jul 4, 2014

Recover LVM Boot partition within a live CD (installing GRUB)

This allows you to recover the Master Boot record when a RAID 5 array fails.


  1. Activate LVM partitions
    sudo mdadm --assemble --scan
    sudo vgchange -a y [name of volume group]
  2. Mount all volumes to a single mount-point
    sudo mount /dev/mapper/[volume group]/[root volume] /mnt/
    sudo mount /dev/mapper/[volume group]/[usr volume] /mnt/usr/
    sudo mount /dev/mapper/[volume group]/[home volume] /mnt/home/
    ... etc
  3. Mount and bind directories for grub to detect the underlying hardware
    sudo mount --bind /dev /mnt/dev
    sudo mount --bind /dev/pts /mnt/dev/pts
    sudo mount --bind /proc /mnt/proc
    sudo mount --bind /sys /mnt/sys
  4. Jump into the new mounted system
    sudo chroot /mnt
  5. Install GRUB
    grub-install /dev/sda
    grub-install --recheck /dev/sda
    update-grub
  6. Exit the environment and restart
    exit
    sudo umount /mnt/dev/pts
    sudo umount /mnt/*
    sudo shutdown -r now

Jul 3, 2014

Recovering a RAID 5 array

Recently had a RAID 5 array fail on me. These are the steps I took to recover the data.

NOTE! The order of the disks in /dev/sdX follows the numbering of the ports on the motherboard. So if a disk is plugged into port 0, it will show up as /dev/sda. Keep this in mind as if you remove a failed disk, it might mess up the references in the array!.
  1. Boot up from a Live CD
  2. Install the software RAID management software
    sudo apt-get install mdadm
  3. Make sure RAID and LVM are unmounted
    sudo vgchange -a n [name of your volume group]  sudo mdadm -S /dev/md0
  4. Copy the failed disk to the new disk (in case the disk was the boot disk, you need to copy that flag across so that your system boots)
    sudo sfdisk -d /dev/sdx | sudo sfdisk /dev/sdy
  5. Check that the disks are the same
    sudo fdisk -l
  6. Mount the RAID array, and remove the failed disk
    sudo mdadm --assemble --scan  sudo mdadm --manage --remove /dev/sdx
  7. Add the new disk
    sudo mdadm --manage --add /dev/sdy
  8. Watch the progress as mdadm rebuilds your RAID array
    sudo cat /proc/mdstat

Apr 11, 2014

Extending the JavaScript HTML5 Canvas object

I have been playing with JavaScript, trying to find new and interesting way to use it in browsers. I have found the wonder that is CANVAS, which allows you to do a whole lot of drawing and animation tasks.

The problem is that the features are low-level, meaning you need to write a lot of code to make anything useful or interesting. A nice technique is to use the prototyping feature of JavaScript to extend the features of canvas. Here are some examples:

if (window.CanvasRenderingContext2D) {
    /**
     * Rounded Rectangle
     */
    CanvasRenderingContext2D.prototype.roundedRect = function(x, y, width, height, radius, colour, border, lineWidth, alpha) {
        // if certain values are not set just exit
        if(!x || !y || !width || !height) { return true; }
        // Set other values
        if (!radius) { radius = 5; }
        if (!alpha) { alpha=1; }
        // Start drawing the rounded rectangle
        this.beginPath();
        this.moveTo(x + radius, y);
        this.lineTo(x + width - radius, y);
        this.quadraticCurveTo(x + width, y, x + width, y + radius);
        this.lineTo(x + width, y + height - radius);
        this.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
        this.lineTo(x + radius, y + height);
        this.quadraticCurveTo(x, y + height, x, y + height - radius);
        this.lineTo(x, y + radius);
        this.quadraticCurveTo(x, y, x + radius, y);
        // Colour it in
        if (colour) {
            this.globalAlpha = alpha;
            this.fillStyle = colour;
            this.fill();
        }
        // Add in optional border
        if (border) {
            this.lineWidth = (lineWidth) ? linewidth : 1;
            this.strokeStyle = border;
            this.stroke();
        }
        // Reset Alpha if it was changed
        this.globalAlpha = 1;
        this.closePath();
    };
    /**
     * Ellipse
     */
    CanvasRenderingContext2D.prototype.ellipse = function(x, y, width, height, colour, border, lineWidth, alpha) {
        // if certain values are not set just exit
        if (!x || !y || !width || !height) { return true; }
        if (!alpha) { alpha=1; }
        // Calculate some points
        var xLeft = x - (width / 2);
        var xRight = x + (width / 2);
        var yTop = y - (height / 2);
        var yBot = y + (height / 2);
        // Draw the ellipse
        this.beginPath();
        // NOTE: The moveTo() is needed to start the drawing from the correct spot
        this.moveTo(x, yTop);
        // Start drawing two bezier curves to create an ellipse
        this.bezierCurveTo(xRight, yTop, xRight, yBot, x, yBot);
        this.bezierCurveTo(xLeft, yBot, xLeft, yTop, x, yTop);
        // Colour it in
        if (colour) {
            this.globalAlpha = alpha;
            this.fillStyle = colour;
            this.fill();
        }
        // Add in optional border
        if (border) {
            this.lineWidth = (lineWidth) ? linewidth : 1;
            this.strokeStyle = border;
            this.stroke();
        }
        // Reset Alpha if it was changed
        this.globalAlpha = 1;
        // Finish the drawing
        this.closePath();
    };
    /**
     * Rounded arcs and circles
     */
    CanvasRenderingContext2D.prototype.circularArc = function(x, y, radius, startAng, endAng, colour, border, lineWidth, enclosed, direction, alpha) {
        // if certain values are not set just exit
        if (!x || !y || !radius) { return true; }
        // Set other values
        if (!alpha) { alpha=1; }
        if (!startAng) { startAng = 0; }
        if (!endAng) { endAng = Math.PI; }
        if (!direction) { direction = false; }
        // Start drawing
        this.beginPath();
        this.arc(x, y, radius, startAng, endAng, direction);
        if (enclosed) {
            this.closePath();
        }
        // Colour it in
        if (colour) {
            this.fillStyle = colour;
            this.fill();
        }
        // Add in optional border
        if (border) {
            this.globalAlpha = alpha;
            this.lineWidth = (lineWidth) ? lineWidth : 1;
            this.strokeStyle = border;
            this.stroke();
        }
     // Reset Alpha if it was changed
        this.globalAlpha = 1;
        // Finish the drawing
        this.closePath();
    };
}

References

Apr 10, 2014

Android HTTP Basic Authentication Service

Been trying to make a simple HTTP Basic Authentication as an Android app (that is mostly backwards compatible).

I am only including all of the necessary resource files. You can define the  icons strings, colours, buttons and styles yourself (just create the appropriate xml file in res/values or res/drawable).

This is my example code:

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?> 
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="au.com.example"
    android:versionCode="1100"
    android:versionName="1.1.00" >
    <!-- Our Target android environment -->
    <uses-sdk
        android:minSdkVersion="10"
        android:targetSdkVersion="19" />
    <!-- Allows the APP to open network sockets -->
    <uses-permission android:name="android.permission.INTERNET" />
    <!-- Device support -->
    <supports-screens
        android:largeScreens="true"
        android:normalScreens="true"
        android:smallScreens="true"
        android:xlargeScreens="true" />
    <!-- Define our application and associated activities -->
    <application
        android:allowBackup="true"
        android:hardwareAccelerated="true"
        android:icon="@drawable/icon"
        android:label="@string/app_name"
        android:theme="@style/CustomTheme" >

        <!-- Our activities -->
        <activity
            android:name=".ActivityLog"
            android:windowSoftInputMode="adjustPan|stateVisible" >
        </activity>
        <activity
            android:name=".ActivityPreference"
            android:windowSoftInputMode="adjustResize|stateVisible" >
        </activity>
        <activity
            android:name=".ActivitySignin"
            android:windowSoftInputMode="adjustPan|stateVisible" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        
        <!-- Signin service -->
        <service
            android:name=".ServiceSignin"
            android:enabled="true"
            android:exported="false"
            android:icon="@drawable/icon"
            android:permission="android.permission.INTERNET" >
        </service>
    </application>
</manifest>

res/xml/preferences.xml

These are our preferences that they user can set (such as the URL to login to as well as the port). This allows you to change the destination server quickly from the UI.

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
    <PreferenceCategory 
        android:title="@string/pref_login_title"
        android:key="pref_key_login_settings">
        <EditTextPreference
            android:key="pref_key_login_url"
            android:summary="@string/pref_login_url_summary"
            android:title="@string/pref_login_url"
            android:defaultValue="example.com.au" />
        <EditTextPreference 
            android:key="pref_key_login_port"
            android:summary="@string/pref_login_port_summary"
            android:title="@string/pref_login_port"
            android:defaultValue="4444" />
    </PreferenceCategory>
</PreferenceScreen>

res/layout/activity_login.xml

<merge xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    tools:context=".ActivityLog" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" >

        <TextView
            android:id="@+id/label_username"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center_vertical|center_horizontal"
            android:text="@string/label_username" />

        <EditText
            android:id="@+id/username"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:ems="10"
            android:inputType="text" >

            <requestFocus />

        </EditText>

        <TextView
            android:id="@+id/label_password"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center_vertical|center_horizontal"
            android:text="@string/label_password" />

        <EditText
            android:id="@+id/password"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:ems="10"
            android:inputType="textPassword" >
        </EditText>

        <Button
            android:id="@+id/btn_login"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:background="@drawable/button_info"
            android:paddingBottom="10dp"
            android:paddingLeft="20dp"
            android:paddingRight="20dp"
            android:paddingTop="10dp"
            android:text="@string/btn_login"
            android:textColor="@color/btn_text" />
    </LinearLayout>
</merge>

res/layout/activity_log.xml

<merge xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    tools:context=".ActivityLog" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" >

        <TextView
            android:id="@+id/label_time"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/label_time" />

        <TimePicker
            android:id="@+id/time"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/label_time" />

        <TextView
            android:id="@+id/label_log"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/label_log" />

        <EditText
            android:id="@+id/log"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:gravity="top"
            android:height="150dp"
            android:hint="@string/hint_log"
            android:inputType="textMultiLine"
            android:minHeight="20dp" >

            <requestFocus />
        </EditText>

        <Button
            android:id="@+id/btn_login"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:background="@drawable/button_info"
            android:paddingBottom="10dp"
            android:paddingLeft="20dp"
            android:paddingRight="20dp"
            android:paddingTop="10dp"
            android:text="@string/btn_submit"
            android:textColor="@color/btn_text" />
    </LinearLayout>
</merge>

res/menu/log.xml

This is simply describes the context menu for ActivityLog.
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
    <item
        android:id="@+id/action_signout"
        android:orderInCategory="100"
        android:showAsAction="never"
        android:title="@string/action_signout"/>
</menu>

res/menu/login.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android" >
    <item
        android:id="@+id/action_settings"
        android:orderInCategory="100"
        android:showAsAction="never"
        android:title="@string/action_settings"/>
</menu>

src/au/com/example/ServiceSignin.java

This is where all the good stuff happens.

package au.com.example;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.concurrent.ExecutionException;

import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;

import android.annotation.SuppressLint;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.preference.PreferenceManager;
import android.support.v4.app.NotificationCompat;
import android.util.Base64;
import android.util.Log;
import android.widget.TextView;

/**
 * Service to handle Login.
 */
public class ServiceSignin extends Service {
/**
* The Base URL
*/
private static String url = "http://example.com.au";
/**
* The port to access
*/
private static String port = "80";
/**
* The shared preferences object
*/
private SharedPreferences sharedPref;
/**
* Listener for changes to shared preference
*/
    public OnSharedPreferenceChangeListener sharedListener = new OnSharedPreferenceChangeListener() {
        @Override
        public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
            Log.i("Service", "A preference has been changed");
            updatePreferences();
        }
    };
/**
* Key to access the Shared Preference value for sub URL
*/
private static final String PREF_URL = "pref_key_login_url";
/**
* Key to access the Shared Preference value for port
*/
private static final String PREF_PORT = "pref_key_login_port";
/**
* Keeps track of all current registered clients.
*/
private ArrayList<Messenger> mClients = new ArrayList<Messenger>();
/**
     * Command to the service to register a client, receiving callbacks
     * from the service.  The Message's replyTo field must be a Messenger of
     * the client where callbacks should be sent.
     */
static final int MSG_REGISTER_CLIENT = 1;
/**
     * Command to the service to unregister a client, to stop receiving callbacks
     * from the service.  The Message's replyTo field must be a Messenger of
     * the client as previously given with MSG_REGISTER_CLIENT.
     */
    static final int MSG_UNREGISTER_CLIENT = 2;
    
    /**
     * Command to the service to request the URL string for the service
     */
    static final int MSG_REQUEST_URL = 3;
    
    /**
     * Command to the service to request the URL string for the service
     */
    static final int MSG_REQUEST_LOGIN = 4;
    
    /**
     * HTTP Client for communicating with server
     */
    public static DefaultHttpClient httpClient;
/**
* Handler of incoming messages from clients.
*/
@SuppressLint("HandlerLeak")
private class IncomingHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
            case MSG_REGISTER_CLIENT:
            // Add the client to the list
                mClients.add(msg.replyTo);
                break;
            case MSG_UNREGISTER_CLIENT:
            // Remove the client from the list
                mClients.remove(msg.replyTo);
                break;
            case MSG_REQUEST_URL:
            try {
            // Send the Message back to client
            Bundle b = new Bundle();
               b.putString("url", url + ":" + port + "/");
               Message reply = Message.obtain(null, MSG_REQUEST_URL);
               reply.setData(b);
msg.replyTo.send(reply);
} catch (RemoteException e) {
Log.e("Service", "Reply error", e);
}
            case MSG_REQUEST_LOGIN:
            try {
            LoginOperation task = new LoginOperation();
            task.execute(url+":"+port+"/login/auth",msg.getData().getString("username"),msg.getData().getString("password"));
            // Send the Message back to client
               Message reply = Message.obtain(null, MSG_REQUEST_LOGIN);
               int success = 0;
if (task.get()) {
success = 1;
}
               reply.arg1 = success;
msg.replyTo.send(reply);
            } catch (InterruptedException e) {
            Log.e("Service", "Interrupted", e);
} catch (ExecutionException e) {
Log.e("Service", "Execution Exception", e);
} catch (RemoteException e) {
Log.e("Service", "Remote Exception", e);
}
            default:
                super.handleMessage(msg);
            }
        }
    }
/**
* Target we publish for clients to send messages to IncomingHandler.
*/
private final Messenger mMessenger = new Messenger(new IncomingHandler());
/**
* For showing and hiding our notification.
*/
private NotificationManager notifyManager;
/**
* Unique Identification Number for the Notification.
* We use it on Notification start, and to cancel it.
*/
private int NOTIFICATION = 10;
/**
* Task for running the login operation
* @see android.os.AsyncTask
*/
private class LoginOperation extends AsyncTask<String, Void, Boolean> {
/**
* Override this method to perform a computation on a background thread.
* @see android.os.AsyncTask#doInBackground(Params... params)
*/
        @Override
        protected Boolean doInBackground(String... login) {
            // We expect exactly three parameters; url, username and password
        if (login.length == 3) {
        try {
        // Our URL to connect to
            URL website = new URL(login[0]);
            Log.i("Service", "URL: "+website.toString());
            // Encode our login details
            String credentials = login[1] + ":" + login[2];
            String base64Encoded = Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP);
            // Create our client connection
            HttpGet getRequest = new HttpGet(website.toString());
            getRequest.addHeader("Authorization", "Basic "+base64Encoded);
            HttpResponse getResponse = httpClient.execute(getRequest);
            if (getResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
            Log.i("Service", "URL Accepted");
            return true;
            } else {
            Log.e("Service", "Not accepted");
            Log.w("Service", "CODE: " + getResponse.getStatusLine().getStatusCode());
            Log.w("Service", "ENCODE: " + base64Encoded);
            Log.w("Service", "CRED: "+credentials);
            Log.w("Service", "URL: "+website.toString());
            }
            } catch (MalformedURLException e) {
Log.e("Service", "Malformed URL", e);
} catch (ClientProtocolException e) {
Log.e("Service", "Client Protocol Exception", e);
e.printStackTrace();
} catch (IOException e) {
Log.e("Service", "IO Exception", e);
}
            }
        return false;
        }

        /**
         * Runs on the UI thread after doInBackground(Params...). The specified result is the value returned by doInBackground(Params...).
         * 
         * @see android.os.AsyncTask#onPostExecute(Result result)
         */
        @Override
        protected void onPostExecute(Boolean result) {
            // might want to change "executed" for the returned string passed
            // into onPostExecute() but that is up to you
        }
    }
/**
* Return the communication channel to the service.
* @see android.app.Service#onBind(Intent)
*/
@Override
    public IBinder onBind(Intent intent) {
        return mMessenger.getBinder();
    }
/**
* Update our values when the Service starts
* @see android.app.Service#onCreate()
*/
@Override
public void onCreate() {
super.onCreate();
// Update our preference objects and listen for changes
sharedPref = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
sharedPref.registerOnSharedPreferenceChangeListener(sharedListener);
updatePreferences();
// Grab a notification manager
notifyManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
// Show notification
showNotification();
// Initialise our HTTP Client server
httpClient = new DefaultHttpClient();
Log.i("Service", "Service Started.");
}
/**
* Called by the system every time a client explicitly starts the service by calling startService(Intent)
* @see android.app.Service#onStartCommand(Intent, int, int)
*/
@Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i("Service", "Received start id " + startId + ": " + intent);
        return super.onStartCommand(intent, flags, startId);
    }
/**
* Called by the system to notify a Service that it is no longer used and is being removed.
* @see android.app.Service#onDestroy()
*/
@Override
    public void onDestroy() {
        super.onDestroy();
        // Delete any notifications
        notifyManager.cancel(NOTIFICATION);
        Log.i("Service", "Service Stopped.");
    }
/**
* Reads the Shared preferences and updates our internal values
*/
public void updatePreferences() {
url = sharedPref.getString(PREF_URL, "error");
port = sharedPref.getString(PREF_PORT, "error");
Log.i("Service", "Preferences updated");
}
/**
     * Show a notification while this service is running
     */
    private void showNotification() {
        // In this sample, we'll use the same text for the ticker and the expanded notification
        CharSequence text = getText(R.string.btn_submit);

        // The PendingIntent to launch our activity if the user selects this notification
        PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, ActivityLog.class), 0);
        
        // Set the icon, scrolling text and timestamp
        Notification notification = new NotificationCompat.Builder(this)
        .setSmallIcon(R.drawable.icon)
        .setContentText(text)
        .setContentTitle("Service")
        .setContentIntent(contentIntent)
        .build();

        // Send the notification.
        // We use a string id because it is a unique number.  We use it later to cancel.
        notifyManager.notify(NOTIFICATION, notification);
    }
}

 src/au/com/example/ActivitySignin.java

This is handles the Login screen.

package au.com.example;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

/**
 * Handles the User Interface for entering and submitting log entries
 * 
 * @author nassar
 */
public class ActivitySignin extends Activity {
/**
     * The username input
     */
    private EditText inputUsername;
    
    /**
     * The password input
     */
    private EditText inputPassword;
    
    /**
     * The Login button
     */
    private Button buttonLogin;
    
    /**
     * Messenger for communicating with service
     */
    private Messenger messageService = null;
    
    /**
     * Flag indicating whether we have called bind on the service.
     */
    private boolean stateIsBound;
    
    /**
     * Controls what happens once the submit button is clicked
     */
    private OnClickListener btnLoginListener = new OnClickListener() {
        public void onClick(View v){
            Log.i("ActivitySignin", "btnLogin has been clicked");
            if (stateIsBound) {
                if (messageService != null) {
                    try {
                    // Send the Message back to client
                Bundle b = new Bundle();
                   b.putString("username", inputUsername.getText().toString());
                   b.putString("password", inputPassword.getText().toString());
                   Message msg = Message.obtain(null, ServiceSignin.MSG_REQUEST_LOGIN, 0, 0);
                   msg.setData(b);
                        msg.replyTo = mMessenger;
                        messageService.send(msg);
                    } catch (RemoteException e) {
                    }
                }
            }
        }
    };
    
    /**
     * Handler of incoming messages from service.
     */
    @SuppressLint("HandlerLeak")
    class IncomingHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
           case ServiceSignin.MSG_REQUEST_LOGIN:
            if (msg.arg1 == 1) {
            Toast.makeText(ActivitySignin.this, "Signed in", Toast.LENGTH_LONG).show();
            Intent intent = new Intent(ActivitySignin.this, ActivityLog.class);
                   startActivity(intent);
            } else {
            Toast.makeText(ActivitySignin.this, "Not signed in", Toast.LENGTH_LONG).show();
            }
               break;
           default:
               super.handleMessage(msg);
            }
        }
    };
    
    /**
     * Target we publish for clients to send messages to IncomingHandler.
     */
    private final Messenger mMessenger = new Messenger(new IncomingHandler());
    
    /**
     * Class for interacting with the main interface of the service.
     */
    private ServiceConnection serviceConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
        // Get a client-side representation of that from the raw service object.
            messageService = new Messenger(service);
            try {
                Message msg = Message.obtain(null, ServiceSignin.MSG_REGISTER_CLIENT);
                msg.replyTo = mMessenger;
                messageService.send(msg);
                Log.i("ActivitySignin", "Service connected");
            } catch (RemoteException e) {
                // In this case the service has crashed before we could even do anything with it
            Log.e("ActivitySignin", "Service crashed before we could do anything with it", e);
            }
        }

        public void onServiceDisconnected(ComponentName className) {
            // This is called when the connection with the service has been unexpectedly disconnected - process crashed.
            messageService = null;
            Log.i("ActivitySignin", "Service has been unexpectedly disconnected - process crashed");
        }
    };
    
    /**
     * Establish a connection with the service.  We use an explicit
     * class name because there is no reason to be able to let other
     * applications replace our component.
     */
    private void doBindService() {
        bindService(new Intent(ActivitySignin.this, ServiceSignin.class), serviceConnection, Context.BIND_AUTO_CREATE);
        stateIsBound = true;
    }
    
    /**
     * Destroy a connection with the service
     */
    private void doUnbindService() {
        if (stateIsBound) {
            // If we have received the service, and hence registered with it, then now is the time to unregister.
            if (messageService != null) {
                try {
                    Message msg = Message.obtain(null, ServiceSignin.MSG_UNREGISTER_CLIENT);
                    msg.replyTo = mMessenger;
                    messageService.send(msg);
                } catch (RemoteException e) {
                    Log.e("ActivitySignin", "Service has been unexpectedly disconnected - process crashed - doUnbindService()", e);
                }
            }
            // Detach our existing connection.
            unbindService(serviceConnection);
            stateIsBound = false;
        }
    }
    
    /**
     * Called after onCreate(Bundle) — or after onRestart() when the activity had been stopped, but is now again being displayed to the user.
     * It will be followed by onResume()
     * 
     * @see android.app.Activity#onStart()
     */
    @Override
    protected void onStart() {
    super.onStart();
        // Start our service (or bind to running service)
    if (!stateIsBound) {
    doBindService();
    Log.i("ActivitySignin", "Starting activity");
    } else {
    Log.i("ActivitySignin", "Already bound");
    }
    }
    
    /**
     * Called when the activity is starting.
     * 
     * @see android.app.Activity#onCreate(android.os.Bundle)
     */
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // Perform the parent operations
        super.onCreate(savedInstanceState);
        
        // Set the layout to display
        setContentView(R.layout.activity_login);
        
        // Set up our inputs from the Activity
        inputUsername = (EditText)findViewById(R.id.username);
        inputPassword = (EditText)findViewById(R.id.password);
        
        // Our Submit button
        buttonLogin = (Button)findViewById(R.id.btn_login);
        
        // Put a listener on the button to capture our input
        buttonLogin.setOnClickListener(btnLoginListener);
    }
    
    /**
     * Initialise the contents of the Activity's options menu.
     * To update the menu every time it is displayed, see onPrepareOptionsMenu(Menu).
     * 
     * @see android.app.Activity#onCreateOptionsMenu(android.view.Menu)
     */
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu items for use in the action bar
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.login, menu);
        return super.onCreateOptionsMenu(menu);
    }
    
    /**
     * This hook is called whenever an item in your options menu is selected.
     * Override default implementation so we can implement activity specific functions
     * (Default implementation is called if the menu item is not handled here.
     * 
     * @see android.app.Activity#onOptionsItemSelected(android.view.MenuItem)
     */
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.action_settings:;
                Intent intent = new Intent(this, ActivityPreference.class);
                startActivity(intent);
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }
    
    /**
     * Perform any final cleanup before an activity is destroyed.
     * @see android.app.Activity#onDestroy()
     */
    @Override
    protected void onDestroy() {
        super.onDestroy();
        try {
            doUnbindService();
        } catch (Throwable t) {
            Log.e("ActivitySignin", "Failed to unbind from the service", t);
        }
    }
}

src/au/com/example/ActivityLog.java

Just a dummy screen that really does nothing.

package au.com.example;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TimePicker;
/**
 * Handles the User Interface for entering and submitting log entries
 *
 * @author nassar
 */
public class ActivityLog extends Activity {
/**
     * The time input
     */
    private TimePicker inputTime;
 
    /**
     * The log input
     */
    private EditText inputLog;
 
    /**
     * The Submit button
     */
    private Button buttonSubmit;
 
    /**
     * Messenger for communicating with service
     */
    private Messenger messageService = null;
 
    /**
     * Flag indicating whether we have called bind on the service.
     */
    private boolean stateIsBound;
 
    /**
     * Controls what happens once the submit button is clicked
     */
    private OnClickListener btnSubmitListener = new OnClickListener() {
        public void onClick(View v){
            Log.i("ActivityLog", "btnSubmit has been clicked");
            if (stateIsBound) {
                if (messageService != null) {
                    try {
                        Message msg = Message.obtain(null, ServiceSignin.MSG_REQUEST_URL, 0, 0);
                        msg.replyTo = mMessenger;
                        messageService.send(msg);
                    } catch (RemoteException e) {
                    }
                }
            }
        }
    };
 
    /**
     * Handler of incoming messages from service.
     */
    @SuppressLint("HandlerLeak")
    class IncomingHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
           case ServiceSignin.MSG_REQUEST_URL:
               String str1 = msg.getData().getString("url");
               Log.i("ActivityLog", "URL: " + str1);
               break;
           default:
               super.handleMessage(msg);
            }
        }
    };
 
    /**
     * Target we publish for clients to send messages to IncomingHandler.
     */
    private final Messenger mMessenger = new Messenger(new IncomingHandler());
 
    /**
     * Class for interacting with the main interface of the service.
     */
    private ServiceConnection serviceConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
        // Get a client-side representation of that from the raw service object.
            messageService = new Messenger(service);
            try {
                Message msg = Message.obtain(null, ServiceSignin.MSG_REGISTER_CLIENT);
                msg.replyTo = mMessenger;
                messageService.send(msg);
                Log.i("ActivityLog", "Service connected");
            } catch (RemoteException e) {
                // In this case the service has crashed before we could even do anything with it
            Log.e("ActivityLog", "Service crashed before we could do anything with it", e);
            }
        }
        public void onServiceDisconnected(ComponentName className) {
            // This is called when the connection with the service has been unexpectedly disconnected - process crashed.
            messageService = null;
            Log.i("ActivityLog", "Service has been unexpectedly disconnected - process crashed");
        }
    };
 
    /**
     * Establish a connection with the service.  We use an explicit
     * class name because there is no reason to be able to let other
     * applications replace our component.
     */
    private void doBindService() {
        bindService(new Intent(ActivityLog.this, ServiceSignin.class), serviceConnection, Context.BIND_AUTO_CREATE);
        stateIsBound = true;
    }
 
    /**
     * Destroy a connection with the service
     */
    private void doUnbindService() {
        if (stateIsBound) {
            // If we have received the service, and hence registered with it, then now is the time to unregister.
            if (messageService != null) {
                try {
                    Message msg = Message.obtain(null, ServiceSignin.MSG_UNREGISTER_CLIENT);
                    msg.replyTo = mMessenger;
                    messageService.send(msg);
                } catch (RemoteException e) {
                    Log.e("ActivityLog", "Service has been unexpectedly disconnected - process crashed - doUnbindService()", e);
                }
            }
            // Detach our existing connection.
            unbindService(serviceConnection);
            stateIsBound = false;
        }
    }
 
    /**
     * Called after onCreate(Bundle) — or after onRestart() when the activity had been stopped, but is now again being displayed to the user.
     * It will be followed by onResume()
     *
     * @see android.app.Activity#onStart()
     */
    @Override
    protected void onStart() {
    super.onStart();
        // Start our service (or bind to running service)
    if (!stateIsBound) {
    doBindService();
    Log.i("ActivityLog", "Starting activity");
    } else {
    Log.i("ActivityLog", "Already bound");
    }
    }
 
    /**
     * Called when the activity is starting.
     *
     * @see android.app.Activity#onCreate(android.os.Bundle)
     */
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // Perform the parent operations
        super.onCreate(savedInstanceState);
     
        // Set the layout to display
        setContentView(R.layout.activity_log);
     
        // Set up our inputs from the Activity
        inputTime = (TimePicker)findViewById(R.id.time);
        inputLog = (EditText)findViewById(R.id.log);
     
        // Our Submit button
        buttonSubmit = (Button)findViewById(R.id.btn_login);
     
        // Put a listener on the button to capture our input
        buttonSubmit.setOnClickListener(btnSubmitListener);
    }
 
    /**
     * Initialise the contents of the Activity's options menu.
     * To update the menu every time it is displayed, see onPrepareOptionsMenu(Menu).
     *
     * @see android.app.Activity#onCreateOptionsMenu(android.view.Menu)
     */
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu items for use in the action bar
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.log, menu);
        return super.onCreateOptionsMenu(menu);
    }
 
    /**
     * This hook is called whenever an item in your options menu is selected.
     * Override default implementation so we can implement activity specific functions
     * (Default implementation is called if the menu item is not handled here.
     *
     * @see android.app.Activity#onOptionsItemSelected(android.view.MenuItem)
     */
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.action_signout:;
                Intent intent = new Intent(this, ActivitySignin.class);
                startActivity(intent);
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }
 
    /**
     * Perform any final cleanup before an activity is destroyed.
     * @see android.app.Activity#onDestroy()
     */
    @Override
    protected void onDestroy() {
        super.onDestroy();
        try {
            doUnbindService();
        } catch (Throwable t) {
            Log.e("ActivityLog", "Failed to unbind from the service", t);
        }
    }
}

src/au/com/example/ActivityPreference.java

This is a simple screen to show and handle changes to our Shared Preferences.

package au.com.example;
import android.annotation.TargetApi;import android.os.Build;import android.os.Bundle;import android.preference.PreferenceActivity;import android.preference.PreferenceFragment;
public class ActivityPreference extends PreferenceActivity {    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);                // Android v11 up uses Fragments, but lower needs Activity        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {            onCreatePreferenceActivity();        } else {            onCreatePreferenceFragment();        }    }        /**     * Wraps legacy {@link #onCreate(Bundle)} code for Android < 3 (i.e. API lvl < 11).     */    @SuppressWarnings("deprecation")    private void onCreatePreferenceActivity() {        addPreferencesFromResource(R.xml.preferences);    }        /**     * Wraps {@link #onCreate(Bundle)} code for Android >= 3 (i.e. API lvl >= 11).     */    @TargetApi(Build.VERSION_CODES.HONEYCOMB)    private void onCreatePreferenceFragment() {        getFragmentManager().beginTransaction()                .replace(android.R.id.content, new MyPreferenceFragment ())                .commit();    }        /**     * Preference Fragment for API lvl >= 11     */    @TargetApi(Build.VERSION_CODES.HONEYCOMB)    public static class MyPreferenceFragment extends PreferenceFragment    {        @Override        public void onCreate(final Bundle savedInstanceState)        {            super.onCreate(savedInstanceState);            addPreferencesFromResource(R.xml.preferences);        }    }}

Resources