- Activate LVM partitions
sudo mdadm --assemble --scan
sudo vgchange -a y [name of volume group] - 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 - 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 - Jump into the new mounted system
sudo chroot /mnt
- Install GRUB
grub-install /dev/sda
grub-install --recheck /dev/sda
update-grub - Exit the environment and restart
exit
sudo umount /mnt/dev/pts
sudo umount /mnt/*
sudo shutdown -r now
This blog is a knowledge dump of all the technical information floating around in my head. It deals with anything involving software, hardware, gadgets, and technology.
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.
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!.
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!.
- Boot up from a Live CD
- Install the software RAID management software
sudo apt-get install mdadm
- Make sure RAID and LVM are unmounted
sudo vgchange -a n [name of your volume group] sudo mdadm -S /dev/md0
- 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
- Check that the disks are the same
sudo fdisk -l
- Mount the RAID array, and remove the failed disk
sudo mdadm --assemble --scan sudo mdadm --manage --remove /dev/sdx
- Add the new disk
sudo mdadm --manage --add /dev/sdy
- 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:
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:
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-sdkandroid:minSdkVersion="10"android:targetSdkVersion="19" /><!-- Allows the APP to open network sockets --><uses-permission android:name="android.permission.INTERNET" /><!-- Device support --><supports-screensandroid:largeScreens="true"android:normalScreens="true"android:smallScreens="true"android:xlargeScreens="true" /><!-- Define our application and associated activities --><applicationandroid:allowBackup="true"android:hardwareAccelerated="true"android:icon="@drawable/icon"android:label="@string/app_name"android:theme="@style/CustomTheme" ><!-- Our activities --><activityandroid:name=".ActivityLog"android:windowSoftInputMode="adjustPan|stateVisible" ></activity><activityandroid:name=".ActivityPreference"android:windowSoftInputMode="adjustResize|stateVisible" ></activity><activityandroid: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 --><serviceandroid: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"><PreferenceCategoryandroid:title="@string/pref_login_title"android:key="pref_key_login_settings"><EditTextPreferenceandroid:key="pref_key_login_url"android:summary="@string/pref_login_url_summary"android:title="@string/pref_login_url"android:defaultValue="example.com.au" /><EditTextPreferenceandroid: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" ><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical" ><TextViewandroid: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" /><EditTextandroid:id="@+id/username"android:layout_width="match_parent"android:layout_height="wrap_content"android:ems="10"android:inputType="text" ><requestFocus /></EditText><TextViewandroid: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" /><EditTextandroid:id="@+id/password"android:layout_width="match_parent"android:layout_height="wrap_content"android:ems="10"android:inputType="textPassword" ></EditText><Buttonandroid: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" ><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical" ><TextViewandroid:id="@+id/label_time"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="@string/label_time" /><TimePickerandroid:id="@+id/time"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="@string/label_time" /><TextViewandroid:id="@+id/label_log"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="@string/label_log" /><EditTextandroid: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><Buttonandroid: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" ><itemandroid: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() {@Overridepublic 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 {@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case MSG_REGISTER_CLIENT:// Add the client to the listmClients.add(msg.replyTo);break;case MSG_UNREGISTER_CLIENT:// Remove the client from the listmClients.remove(msg.replyTo);break;case MSG_REQUEST_URL:try {// Send the Message back to clientBundle 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 clientMessage 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)*/@Overrideprotected Boolean doInBackground(String... login) {// We expect exactly three parameters; url, username and passwordif (login.length == 3) {try {// Our URL to connect toURL website = new URL(login[0]);Log.i("Service", "URL: "+website.toString());// Encode our login detailsString credentials = login[1] + ":" + login[2];String base64Encoded = Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP);// Create our client connectionHttpGet 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)*/@Overrideprotected 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)*/@Overridepublic IBinder onBind(Intent intent) {return mMessenger.getBinder();}/*** Update our values when the Service starts** @see android.app.Service#onCreate()*/@Overridepublic void onCreate() {super.onCreate();// Update our preference objects and listen for changessharedPref = PreferenceManager.getDefaultSharedPreferences(getBaseContext());sharedPref.registerOnSharedPreferenceChangeListener(sharedListener);updatePreferences();// Grab a notification managernotifyManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);// Show notificationshowNotification();// Initialise our HTTP Client serverhttpClient = 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)*/@Overridepublic 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()*/@Overridepublic void onDestroy() {super.onDestroy();// Delete any notificationsnotifyManager.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 notificationCharSequence text = getText(R.string.btn_submit);// The PendingIntent to launch our activity if the user selects this notificationPendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, ActivityLog.class), 0);// Set the icon, scrolling text and timestampNotification 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 clientBundle 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 {@Overridepublic 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 itLog.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()*/@Overrideprotected 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)*/@Overrideprotected void onCreate(Bundle savedInstanceState) {// Perform the parent operationssuper.onCreate(savedInstanceState);// Set the layout to displaysetContentView(R.layout.activity_login);// Set up our inputs from the ActivityinputUsername = (EditText)findViewById(R.id.username);inputPassword = (EditText)findViewById(R.id.password);// Our Submit buttonbuttonLogin = (Button)findViewById(R.id.btn_login);// Put a listener on the button to capture our inputbuttonLogin.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)*/@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu items for use in the action barMenuInflater 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)*/@Overridepublic 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()*/@Overrideprotected 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
- AsyncTask reference from Android Developer reference
- AsyncTask example from StackOverflow
- AsyncTask tutorial from Vogella
- Services guide from Android Developer reference
- Service reference from Android Developer reference
- Activity reference from Android Developer reference
- Example code for messaging between an Activity and a Service by Philipp Heckel
- Another example code for messaging between an Activity and a Service from StackOverflow
- Services example from Vogella
- Maintaining Sessions from StackOverflow
- HTTP Authentication in android from StackOverflow
- Another HTTP Authentication question from StackOverflow
- Basic HTTP Authentication from Leocadio
- HTTP Status code from Android Developer reference
- Bound Services from Android Developer reference
- Creating Background Services from Android Developer reference
- Settings from Android Developer reference
- Saving Files from Android Developer reference
- Shared Preferences from Android reference
- How to create a Notification from StackOverflow
Subscribe to:
Posts (Atom)