package com.crcmike;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.File;
import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.widget.Button;
import android.widget.EditText;
import android.widget.RadioButton;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Toast;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;

public class crcMike extends Activity implements OnClickListener {
private static final char[] HEX_CHARS = {'0', '1', '2', '3',
'4', '5', '6', '7',
'8', '9', 'a', 'b',
'c', 'd', 'e', 'f',};

private static final String TAG = "crcMike";
private String mResults = null;
Button buttonCalc;
RadioButton radioC, radioF;
EditText editText;

// Need handler for callbacks to the UI thread
final Handler mHandler = new Handler(){

public void handleMessage(Message msg) {

Log.i(TAG, "Got an incoming message from the child thread - " + (String)msg.obj);

/*
* Handle the message coming from the child thread.
*/
Toast.makeText(getApplicationContext(), (String)msg.obj + "\n", Toast.LENGTH_LONG).show();
}
};


// Create runnable for posting
final Runnable mUpdateResults = new Runnable() {
public void run() {
Message msg = mHandler.obtainMessage();
msg.obj = mHandler.getLooper().getThread().getName() + " says Hello";
mHandler.sendMessage(msg);
Log.i(TAG, "Send a message to the child thread - " + (String)msg.obj);

updateResultsInUi();
}
};

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

Log.d(TAG, "starting...");

// find views by id
editText = (EditText)findViewById(R.id.editText);
radioC = (RadioButton)findViewById(R.id.radioC);
radioF = (RadioButton)findViewById(R.id.radioF);
buttonCalc = (Button)findViewById(R.id.buttonCalc);

// add listener
buttonCalc.setOnClickListener(this);

editText.setText("32");

}

public void onClick(View v){

switch(v.getId()){

case R.id.buttonCalc:

startLongRunningOperation();

// do something when the button is clicked

// if (editText.getText().length() == 0) {
// Toast.makeText(getApplicationContext(), "Please enter a valid temperature!", Toast.LENGTH_LONG).show();
// return;
// }

float inputValue = Float.parseFloat(editText.getText().toString());
if (radioC.isChecked()) {
editText.setText(String
.valueOf(fToC(inputValue)));
} else {
editText.setText(String
.valueOf(cToF(inputValue)));
}

// switch the selected buttons
if (radioF.isChecked()) {
radioF.setChecked(false);
radioC.setChecked(true);
} else {
radioF.setChecked(true);
radioC.setChecked(false);
}

// need to add List interface?

default:
break;
}
}

protected void startLongRunningOperation() {
// Fire off a thread to do some work that we shouldn't do directly in the UI thread
Thread t = new Thread() {
public void run() {
mResults = crc_calc();
mHandler.post(mUpdateResults);
}
};
t.start();

Log.i(TAG, "Main handler is bound to - " + mHandler.getLooper().getThread().getName());
}



private void updateResultsInUi() {
// Back in the UI thread -- update our UI elements based on the data in mResults
Toast.makeText(getApplicationContext(), mResults, Toast.LENGTH_LONG).show();
Log.d("huh", "mResults: " + mResults);
Log.i("huh", "updateUI - " + (String)mHandler.getLooper().getThread().getName());
}

public String crc_calc() {
final String INNER_TAG = "checksum";

byte[] buf = new byte[65536];
int num_read;
String result = null;
Message toMain = mHandler.obtainMessage();

// the external storage is assumed as connected here!
String FILENAME = "test.log"; //hard coded filename!
File path = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DOWNLOADS);
File file = new File(path,FILENAME);

try{
/*
* testing the MD5 hash computation.
*/
java.security.MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
InputStream in = new FileInputStream(file);
//InputStream in = new StringBufferInputStream("dasdadad");
while ((num_read = in.read(buf)) != -1) {
digest.update(buf, 0, num_read);
}
//Toast.makeText(getApplicationContext(), asHex(digest.digest()), Toast.LENGTH_LONG).show();

result = asHex(digest.digest());
toMain.obj = mHandler.getLooper().getThread().getName() + ": " + result;
in.close();

}catch (IOException e){
//Toast.makeText(getApplicationContext(), "Error reading from " + file, Toast.LENGTH_LONG).show();
toMain.obj = mHandler.getLooper().getThread().getName() + "Error reading from " + file.toString();
Log.d(INNER_TAG, "IOException");
}catch (Exception e){
//Toast.makeText(getApplicationContext(), e.toString() + " / ID = " + id, Toast.LENGTH_LONG).show();
toMain.obj = mHandler.getLooper().getThread().getName() + "Exception";
Log.d(INNER_TAG, "Exception");
}

/*
* Send the processing result back to the main thread.
*/
//Message toMain = mMainHandler.obtainMessage();
//toMain.obj = "This is " + this.getLooper().getThread().getName() +
// ". Did you send me \"" + (String)msg.obj + "\"?";
mHandler.sendMessage(toMain);
Log.i(INNER_TAG, "Send a message to the main thread - " + (String)toMain.obj);

return(result);
}

// Converts to celcius
private float fToC(float fahrenheit) {
return ((fahrenheit - 32) * 5 / 9);
}

// Converts to fahrenheit
private float cToF(float celsius) {
return ((celsius * 9) / 5) + 32;
}

/*
* Turns array of bytes into string representing each byte as
* unsigned hex number.
*
* @param hash Array of bytes to convert to hex-string
* @return Generated hex string
*/
public static String asHex (byte hash[]) {
char buf[] = new char[hash.length * 2];
for (int i = 0, x = 0; i < hash.length; i++) {
buf[x++] = HEX_CHARS[(hash[i] >>> 4) & 0xf];
buf[x++] = HEX_CHARS[hash[i] & 0xf];
}
return new String(buf);
}

}



/***************************************/

PROBLEM:

As per,
http://developer.android.com/guide/appendix/faq/commontasks.html#threading

I was expecting this to cause the workload to operate in as a child thread, but instead, it seems to still be apart of the main thread? Here's logcat output:

I/crcMike ( 2469): Main handler is bound to - main
I/checksum( 2469): Send a message to the main thread - main: 7933d0f2409ca27b510912b6a64527a3
I/crcMike ( 2469): Got an incoming message from the child thread - main: 7933d0f2409ca27b510912b6a64527a3
I/crcMike ( 2469): Send a message to the child thread - main says Hello
D/huh ( 2469): mResults: 7933d0f2409ca27b510912b6a64527a3
I/huh ( 2469): updateUI - main
I/crcMike ( 2469): Got an incoming message from the child thread - main says Hello

The program above displays and activity, on clicking a button (ignore the temp conversion) it computes the MD5 hash of a file on the SD card; the idea was to do this computation as a separate thread.

So, is this how a runnable thread should work?

Your assistance is much appreciated, thanks :)