/**
 * Android Suite 
 * Purpose:	Measure Mobile App Performance
 * Built on Eclipse for Linux, Ubuntu 12.04 LTS
 * By:	Ramon Luis De Jesus
 * On:	May 30, 2013	1:30pm
 * Note:	Integer values don't matter much on MainActivity.java
 * 			Values here are set for reference or overwrite actual defaults on val's x.
 */
package gov.nist.androidsuite;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.media.RingtoneManager;
import android.os.AsyncTask;
import android.os.BadParcelableException;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Vibrator;
import android.support.v4.app.NotificationCompat;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.Menu;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {

	// Assign Progress bar
	private static ProgressBar pbProgress;

	// Assign Progress TextView
	private static TextView tvProgress;

	/**
	 * Globals
	 */
	// Assign for BufferToTrace EditText
	private EditText etBufferToTrace;
	public static int BufferToTrace = 8000000;
	public static final int NUMFUN = 6;
	public static List<String> ElapsedTimes;
	
	// Use to store and later delete our traceFiles
	public static File TracesDirectory;

	/**
	 * Val 1 Values
	 */
	// Assign for Val1Innerloop EditText
	private EditText etVal1InnerLoop;
	// Assign for Val1OuterLoop EditText
	private EditText etVal1OuterLoop;

	// Assign for Val1RepeatTimes EditText
	private EditText etVal1Repeat;
	// default Val1RepeatTimes
	public static long Val1RepeatTimes = 1;

	// / default val1 reversed state
	private Boolean Val1Reverse = false;
	// / default innerloop
	private long Val1InnerLoop = 256;
	// / default outerloop, time of the process "250000" is a random default
	// number.
	private long Val1OuterLoop = 256000 / Val1InnerLoop;

	/**
	 * Val 2 Values
	 */
	// Assign for Val1Innerloop EditText
	private EditText etVal2InnerLoop;
	// / default innerloop
	private long Val2InnerLoop = 800000;

	// Assign for Val2RepeatTimes EditText
	private EditText etVal2Repeat;
	// default Val2RepeatTimes
	public static long Val2RepeatTimes = 1;

	/**
	 * Val 3 Values
	 */
	// Assign for Val3FN1LOOP EditText
	private EditText etVal3FN1Loop;
	// Assign for Val3FN2LOOP EditText
	private EditText etVal3FN2Loop;
	// / default fn1loop
	private long Val3FN1Loop = 125000;
	// / default fn2loop, time of the process.
	private long Val3FN2Loop = Val3FN1Loop * 2;

	// Assign for Val3RepeatTimes EditText
	private EditText etVal3Repeat;
	// default Val3RepeatTimes
	public static long Val3RepeatTimes = 1;

	/**
	 * Val 4 Values
	 */
	// Assign for Val4FN1LOOP EditText
	private EditText etVal4FN1Loop;
	// Assign for Val4FN2LOOP EditText
	private EditText etVal4FN2Loop;
	// / default fn1loop
	private long Val4FN1Loop = 400000;
	// / default fn2loop, time of the process.
	private long Val4FN2Loop = 400000;

	// Assign for Val4RepeatTimes EditText
	private EditText etVal4Repeat;
	// default Val4RepeatTimes
	public static long Val4RepeatTimes = 1;

	/**
	 * Val 5 Values
	 */
	// Assign for Val5FN1LOOP EditText
	private EditText etVal5FN1Loop;
	// Assign for Val5FN2LOOP EditText
	private EditText etVal5FN2Loop;
	// / default fn1loop
	private long Val5FN1Loop = 250000;
	// / default fn2loop, time of the process.
	private long Val5FN2Loop = Val5FN1Loop * 2;

	// Assign for Val5RepeatTimes EditText
	private EditText etVal5Repeat;
	// default Val5RepeatTimes
	public static long Val5RepeatTimes = 1;

	/**
	 * Val 6 Values
	 */
	// Assign for Val6LeafLoop EditText
	private EditText etVal6LeafLoop;
	// Assign for Val6EachLoop EditText
	private EditText etVal6EachLoop;
	// / Assign for Val6Depth EditText
	private EditText etVal6Depth;
	// / default LEAFLOOP
	private long Val6LeafLoop = 1000000;
	// / default EACHLOOP, time of the process.
	private long Val6EachLoop = 0;
	// / constant MAX Val6DEPTH is 132 for Android Droidx phone
	public static final long Val6DEPTH = 132;
	// / default Val6Depth
	private long Val6Depth = 132;

	// Assign for Val6RepeatTimes EditText
	private EditText etVal6Repeat;
	// default Val6RepeatTimes
	public static long Val6RepeatTimes = 1;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		setContentView(R.layout.activity_main);
		
		WhoAmI();
		
		TracesDirectory = new File(Environment.getExternalStorageDirectory()+"/Traces");
		TracesDirectory.mkdirs();
		
		pbProgress = (ProgressBar) findViewById(R.id.pbProgress);

		pbProgress.setVisibility(View.GONE);

		tvProgress = (TextView) findViewById(R.id.tvProgress);

		// Keep screen on, even if the device its not charging.
		// Bug fixer for stops in the service.
		getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

		// Hack, brings windows phone feel in keyboard controlling. If you touch
		// outside the keyboard, the keyboard gets hidden.
		final View touchView = findViewById(R.id.Main);
		touchView.setOnTouchListener(new View.OnTouchListener() {
			@Override
			public boolean onTouch(View v, MotionEvent event) {
				try {
					InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
					imm.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY,
							0);
				} catch (Exception e) {
					Log.e("Error", e.getMessage());
				}
				return true;
			}
		});

		/**
		 * Global listeners
		 */
		etBufferToTrace = (EditText) findViewById(R.id.etBufferToTrace);
		etBufferToTrace.addTextChangedListener(new TextWatcher() {
			@Override
			public void afterTextChanged(Editable s) {
				try {
					if (etBufferToTrace.getText().toString().length() > 6) {
						int x = Integer.parseInt(etBufferToTrace.getText()
								.toString());
						if (x > 0 && x < 2000000000) {
							BufferToTrace = x;
						} else {
							throw new BadParcelableException("");
						}
					} else {
						BufferToTrace = Integer.parseInt(etBufferToTrace
								.getHint().toString());
					}
				} catch (Exception ex) {
					MessageBox("Invalid number of buffer to trace!");
				}
			}

			@Override
			public void beforeTextChanged(CharSequence s, int start, int count,
					int after) {
			}

			@Override
			public void onTextChanged(CharSequence s, int start, int before,
					int count) {
			}
		});

		/**
		 * Val 1 listeners
		 */
		etVal1InnerLoop = (EditText) findViewById(R.id.etVal1InnerLoop);
		etVal1OuterLoop = (EditText) findViewById(R.id.etVal1OuterLoop);
		etVal1Repeat = (EditText) findViewById(R.id.etVal1RepeatTimes);
		etVal1Repeat.addTextChangedListener(new TextWatcher() {
			@Override
			public void afterTextChanged(Editable s) {
				try {
					if (etVal1Repeat.getText().toString().length() != 0) {
						long x = Long.parseLong(etVal1Repeat.getText()
								.toString());
						if (x > 0) {
							Val1RepeatTimes = x;
						} else {
							throw new BadParcelableException("");
						}
					} else {
						Val1RepeatTimes = Long.parseLong(etVal1Repeat.getHint()
								.toString());
					}
				} catch (Exception ex) {
					MessageBox("Invalid number for repeat");
				}
			}

			@Override
			public void beforeTextChanged(CharSequence s, int start, int count,
					int after) {
			}

			@Override
			public void onTextChanged(CharSequence s, int start, int before,
					int count) {
			}
		});
		etVal1InnerLoop.addTextChangedListener(new TextWatcher() {
			@Override
			public void afterTextChanged(Editable s) {
				try {
					if (etVal1InnerLoop.getText().toString().length() != 0) {
						long x = Long.parseLong(etVal1InnerLoop.getText()
								.toString());
						if (x > 0) {
							Val1InnerLoop = x;
						} else {
							throw new BadParcelableException("");
						}
					} else {
						Val1InnerLoop = Long.parseLong(etVal1InnerLoop
								.getHint().toString());
					}
				} catch (Exception ex) {
					MessageBox("Invalid number of leaf functions!");
				}
			}

			@Override
			public void beforeTextChanged(CharSequence s, int start, int count,
					int after) {
			}

			@Override
			public void onTextChanged(CharSequence s, int start, int before,
					int count) {
			}
		});
		etVal1OuterLoop.addTextChangedListener(new TextWatcher() {
			@Override
			public void afterTextChanged(Editable s) {
				try {
					if (etVal1OuterLoop.getText().toString().length() != 0) {
						long x = Long.parseLong(etVal1OuterLoop.getText()
								.toString());
						if (x > 0) {
							Val1OuterLoop = x;
						} else {
							throw new BadParcelableException("");
						}
					} else {
						Val1OuterLoop = 256000 / Val1InnerLoop;
					}
				} catch (Exception ex) {
					MessageBox("Invalid number of iterations!");
				}
			}

			@Override
			public void beforeTextChanged(CharSequence s, int start, int count,
					int after) {
			}

			@Override
			public void onTextChanged(CharSequence s, int start, int before,
					int count) {
			}
		});

		/**
		 * Val 2 listeners
		 */
		etVal2Repeat = (EditText) findViewById(R.id.etVal2RepeatTimes);
		etVal2Repeat.addTextChangedListener(new TextWatcher() {
			@Override
			public void afterTextChanged(Editable s) {
				try {
					if (etVal2Repeat.getText().toString().length() != 0) {
						long x = Long.parseLong(etVal2Repeat.getText()
								.toString());
						if (x > 0) {
							Val2RepeatTimes = x;
						} else {
							throw new BadParcelableException("");
						}
					} else {
						Val2RepeatTimes = Long.parseLong(etVal2Repeat.getHint()
								.toString());
					}
				} catch (Exception ex) {
					MessageBox("Invalid number for repeat");
				}
			}

			@Override
			public void beforeTextChanged(CharSequence s, int start, int count,
					int after) {
			}

			@Override
			public void onTextChanged(CharSequence s, int start, int before,
					int count) {
			}
		});
		etVal2InnerLoop = (EditText) findViewById(R.id.etVal2InnerLoop);
		etVal2InnerLoop.addTextChangedListener(new TextWatcher() {
			@Override
			public void afterTextChanged(Editable s) {
				try {
					if (etVal2InnerLoop.getText().toString().length() != 0) {
						long x = Long.parseLong(etVal2InnerLoop.getText()
								.toString());
						if (x > 0) {
							Val2InnerLoop = x;
						} else {
							throw new BadParcelableException("");
						}
					} else {
						Val2InnerLoop = Long.parseLong(etVal2InnerLoop
								.getHint().toString());
					}
				} catch (Exception ex) {
					MessageBox("Invalid number of leaf functions!");
				}

			}

			@Override
			public void beforeTextChanged(CharSequence s, int start, int count,
					int after) {
			}

			@Override
			public void onTextChanged(CharSequence s, int start, int before,
					int count) {
			}
		});
		/**
		 * Val 3 listeners
		 */
		etVal3Repeat = (EditText) findViewById(R.id.etVal3RepeatTimes);
		etVal3Repeat.addTextChangedListener(new TextWatcher() {
			@Override
			public void afterTextChanged(Editable s) {
				try {
					if (etVal3Repeat.getText().toString().length() != 0) {
						long x = Long.parseLong(etVal3Repeat.getText()
								.toString());
						if (x > 0) {
							Val3RepeatTimes = x;
						} else {
							throw new BadParcelableException("");
						}
					} else {
						Val3RepeatTimes = Long.parseLong(etVal3Repeat.getHint()
								.toString());
					}
				} catch (Exception ex) {
					MessageBox("Invalid number for repeat");
				}
			}

			@Override
			public void beforeTextChanged(CharSequence s, int start, int count,
					int after) {
			}

			@Override
			public void onTextChanged(CharSequence s, int start, int before,
					int count) {
			}
		});
		etVal3FN1Loop = (EditText) findViewById(R.id.etVal3FN1Loop);
		etVal3FN2Loop = (EditText) findViewById(R.id.etVal3FN2Loop);
		etVal3FN1Loop.addTextChangedListener(new TextWatcher() {
			@Override
			public void afterTextChanged(Editable s) {
				try {
					if (etVal3FN1Loop.getText().toString().length() != 0) {
						long x = Long.parseLong(etVal3FN1Loop.getText()
								.toString());
						if (x > 0) {
							Val3FN1Loop = x;
						} else {
							throw new BadParcelableException("");
						}
					} else {
						Val3FN1Loop = Long.parseLong(etVal3FN1Loop.getHint()
								.toString());
					}
				} catch (Exception ex) {
					MessageBox("Invalid number of busy-work iterations in cycfn1.");
				}
			}

			@Override
			public void beforeTextChanged(CharSequence s, int start, int count,
					int after) {
			}

			@Override
			public void onTextChanged(CharSequence s, int start, int before,
					int count) {
			}
		});
		etVal3FN2Loop.addTextChangedListener(new TextWatcher() {
			@Override
			public void afterTextChanged(Editable s) {
				try {
					if (etVal3FN2Loop.getText().toString().length() != 0) {
						long x = Long.parseLong(etVal3FN2Loop.getText()
								.toString());
						if (x > 0) {
							Val3FN2Loop = x;
						} else {
							throw new BadParcelableException("");
						}
					} else {
						Val3FN2Loop = Long.parseLong(etVal3FN2Loop.getHint()
								.toString());
					}
				} catch (Exception ex) {
					MessageBox("Invalid number of busy-work iterations in cycfn2.");
				}
			}

			@Override
			public void beforeTextChanged(CharSequence s, int start, int count,
					int after) {
			}

			@Override
			public void onTextChanged(CharSequence s, int start, int before,
					int count) {
			}
		});

		/**
		 * Val 4 listeners
		 */
		etVal4Repeat = (EditText) findViewById(R.id.etVal4RepeatTimes);
		etVal4Repeat.addTextChangedListener(new TextWatcher() {
			@Override
			public void afterTextChanged(Editable s) {
				try {
					if (etVal4Repeat.getText().toString().length() != 0) {
						long x = Long.parseLong(etVal4Repeat.getText()
								.toString());
						if (x > 0) {
							Val4RepeatTimes = x;
						} else {
							throw new BadParcelableException("");
						}
					} else {
						Val4RepeatTimes = Long.parseLong(etVal4Repeat.getHint()
								.toString());
					}
				} catch (Exception ex) {
					MessageBox("Invalid number for repeat");
				}
			}

			@Override
			public void beforeTextChanged(CharSequence s, int start, int count,
					int after) {
			}

			@Override
			public void onTextChanged(CharSequence s, int start, int before,
					int count) {
			}
		});

		etVal4FN1Loop = (EditText) findViewById(R.id.etVal4FN1Loop);
		etVal4FN2Loop = (EditText) findViewById(R.id.etVal4FN2Loop);
		etVal4FN1Loop.addTextChangedListener(new TextWatcher() {
			@Override
			public void afterTextChanged(Editable s) {
				try {
					if (etVal4FN1Loop.getText().toString().length() != 0) {
						long x = Long.parseLong(etVal4FN1Loop.getText()
								.toString());
						if (x > 0) {
							Val4FN1Loop = x;
						} else {
							throw new BadParcelableException("");
						}
					} else {
						Val4FN1Loop = Long.parseLong(etVal4FN1Loop.getHint()
								.toString());
					}
				} catch (Exception ex) {
					MessageBox("Invalid number of leaf functions!");
				}
			}

			@Override
			public void beforeTextChanged(CharSequence s, int start, int count,
					int after) {
			}

			@Override
			public void onTextChanged(CharSequence s, int start, int before,
					int count) {
			}
		});
		etVal4FN2Loop.addTextChangedListener(new TextWatcher() {
			@Override
			public void afterTextChanged(Editable s) {
				try {
					if (etVal4FN2Loop.getText().toString().length() != 0) {
						long x = Long.parseLong(etVal4FN2Loop.getText()
								.toString());
						if (x > 0) {
							Val4FN2Loop = x;
						} else {
							throw new BadParcelableException("");
						}
					} else {
						Val4FN2Loop = Long.parseLong(etVal4FN2Loop.getHint()
								.toString());
					}
				} catch (Exception ex) {
					MessageBox("Invalid number of iterations!");
				}
			}

			@Override
			public void beforeTextChanged(CharSequence s, int start, int count,
					int after) {
			}

			@Override
			public void onTextChanged(CharSequence s, int start, int before,
					int count) {
			}
		});

		/**
		 * Val 5 listeners
		 */
		etVal5Repeat = (EditText) findViewById(R.id.etVal5RepeatTimes);
		etVal5Repeat.addTextChangedListener(new TextWatcher() {
			@Override
			public void afterTextChanged(Editable s) {
				try {
					if (etVal5Repeat.getText().toString().length() != 0) {
						long x = Long.parseLong(etVal5Repeat.getText()
								.toString());
						if (x > 0) {
							Val5RepeatTimes = x;
						} else {
							throw new BadParcelableException("");
						}
					} else {
						Val5RepeatTimes = Long.parseLong(etVal5Repeat.getHint()
								.toString());
					}
				} catch (Exception ex) {
					MessageBox("Invalid number for repeat");
				}
			}

			@Override
			public void beforeTextChanged(CharSequence s, int start, int count,
					int after) {
			}

			@Override
			public void onTextChanged(CharSequence s, int start, int before,
					int count) {
			}
		});
		etVal5FN1Loop = (EditText) findViewById(R.id.etVal5FN1Loop);
		etVal5FN2Loop = (EditText) findViewById(R.id.etVal5FN2Loop);
		etVal5FN1Loop.addTextChangedListener(new TextWatcher() {
			@Override
			public void afterTextChanged(Editable s) {
				try {
					if (etVal5FN1Loop.getText().toString().length() != 0) {
						long x = Long.parseLong(etVal5FN1Loop.getText()
								.toString());
						if (x > 0) {
							Val5FN1Loop = x;
						} else {
							throw new BadParcelableException("");
						}
					} else {
						Val5FN1Loop = Long.parseLong(etVal5FN1Loop.getHint()
								.toString());
					}
				} catch (Exception ex) {
					MessageBox("Invalid number of busy-work iterations in top invocation.");
				}
			}

			@Override
			public void beforeTextChanged(CharSequence s, int start, int count,
					int after) {
			}

			@Override
			public void onTextChanged(CharSequence s, int start, int before,
					int count) {
			}
		});
		etVal5FN2Loop.addTextChangedListener(new TextWatcher() {
			@Override
			public void afterTextChanged(Editable s) {
				try {
					if (etVal5FN2Loop.getText().toString().length() != 0) {
						long x = Long.parseLong(etVal5FN2Loop.getText()
								.toString());
						if (x > 0) {
							Val5FN2Loop = x;
						} else {
							throw new BadParcelableException("");
						}
					} else {
						Val5FN2Loop = Long.parseLong(etVal5FN2Loop.getHint()
								.toString());
					}
				} catch (Exception ex) {
					MessageBox("Invalid number of busy-work iterations in leaf invocation.");
				}
			}

			@Override
			public void beforeTextChanged(CharSequence s, int start, int count,
					int after) {
			}

			@Override
			public void onTextChanged(CharSequence s, int start, int before,
					int count) {
			}
		});

		/**
		 * Val 6 listeners
		 */
		etVal6Repeat = (EditText) findViewById(R.id.etVal6RepeatTimes);
		etVal6Repeat.addTextChangedListener(new TextWatcher() {
			@Override
			public void afterTextChanged(Editable s) {
				try {
					if (etVal6Repeat.getText().toString().length() != 0) {
						long x = Long.parseLong(etVal6Repeat.getText()
								.toString());
						if (x > 0) {
							Val6RepeatTimes = x;
						} else {
							throw new BadParcelableException("");
						}
					} else {
						Val6RepeatTimes = Long.parseLong(etVal6Repeat.getHint()
								.toString());
					}
				} catch (Exception ex) {
					MessageBox("Invalid number for repeat");
				}
			}

			@Override
			public void beforeTextChanged(CharSequence s, int start, int count,
					int after) {
			}

			@Override
			public void onTextChanged(CharSequence s, int start, int before,
					int count) {
			}
		});
		etVal6LeafLoop = (EditText) findViewById(R.id.etVal6LeafLoop);
		etVal6EachLoop = (EditText) findViewById(R.id.etVal6EachLoop);
		etVal6Depth = (EditText) findViewById(R.id.etVal6Depth);
		etVal6LeafLoop.addTextChangedListener(new TextWatcher() {
			@Override
			public void afterTextChanged(Editable s) {
				try {
					if (etVal6LeafLoop.getText().toString().length() != 0) {
						long x = Long.parseLong(etVal6LeafLoop.getText()
								.toString());
						if (x > 0) {
							Val6LeafLoop = x;
						} else {
							throw new BadParcelableException("");
						}
					} else {
						Val6LeafLoop = Long.parseLong(etVal6LeafLoop.getHint()
								.toString());
					}
				} catch (Exception ex) {
					MessageBox("Invalid number of iterations in leaf invocation.");
				}
			}

			@Override
			public void beforeTextChanged(CharSequence s, int start, int count,
					int after) {
			}

			@Override
			public void onTextChanged(CharSequence s, int start, int before,
					int count) {
			}
		});
		etVal6EachLoop.addTextChangedListener(new TextWatcher() {
			@Override
			public void afterTextChanged(Editable s) {
				try {
					if (etVal6EachLoop.getText().toString().length() != 0) {
						long x = Long.parseLong(etVal6EachLoop.getText()
								.toString());
						if (x >= 0) {
							Val6EachLoop = x;
						} else {
							throw new BadParcelableException("");
						}
					} else {
						Val6EachLoop = Long.parseLong(etVal6EachLoop.getHint()
								.toString());
					}
				} catch (Exception ex) {
					MessageBox("Invalid number of iterations in non-leaf invocations.");
				}
			}

			@Override
			public void beforeTextChanged(CharSequence s, int start, int count,
					int after) {
			}

			@Override
			public void onTextChanged(CharSequence s, int start, int before,
					int count) {
			}
		});
		etVal6Depth.addTextChangedListener(new TextWatcher() {
			@Override
			public void afterTextChanged(Editable s) {
				try {
					if (etVal6Depth.getText().toString().length() != 0) {
						long x = Long.parseLong(etVal6Depth.getText()
								.toString());
						if (x > 0 & x <= Val6DEPTH) {
							Val6Depth = x;
						} else {
							throw new BadParcelableException("");
						}
					} else {
						Val6Depth = Long.parseLong(etVal6Depth.getHint()
								.toString());
					}
				} catch (Exception ex) {
					MessageBox("Invalid number of depth of recursion.");
				}
			}

			@Override
			public void beforeTextChanged(CharSequence s, int start, int count,
					int after) {
			}

			@Override
			public void onTextChanged(CharSequence s, int start, int before,
					int count) {
			}
		});

	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

	/**
	 * Global Click Events
	 */	
	public void btnCleanClicked(View v) {

		if (!pbProgress.isShown()) {
			pbProgress.setVisibility(View.VISIBLE);
			UpdateProgressMessage("Deleting...");
			DeleteTraceFiles delete = new DeleteTraceFiles();
			delete.Start();
		}
	}
	
	public void onDestroy() {
		super.onDestroy();
		System.exit(0);
	}
	
	public void btnExitClicked(View v) {

		Vibrate();
		finish();
	}

	/**
	 * Val 1 Click Events
	 * 
	 * @param v
	 */
	// Event of btnVal1 Clicked
	public void btnVal1Clicked(View v) {
		if (!pbProgress.isShown()) {
			pbProgress.setVisibility(View.VISIBLE);
			ElapsedTimes = new ArrayList<String>();
			try {
				new AsyncTask<String, Integer, Boolean>() {
					@Override
					protected Boolean doInBackground(String... params) {
						for (int i = 1; i <= Val1RepeatTimes; i++) {
							publishProgress(i);
							Val1 runVal1 = new Val1();
							// Start our test and return a value
							MicroTimer time = new MicroTimer();
							runVal1.Start(i, Val1Reverse, Val1InnerLoop,
									Val1OuterLoop, BufferToTrace);
							ElapsedTimes.add(time.getFinalTime());
						}
						return null;
					}

					@Override
					protected void onProgressUpdate(Integer... values) {
						UpdateProgressMessage("ValOne: "
								+ Integer.toString(values[0]) + "/"
								+ Long.toString(Val1RepeatTimes));
						super.onProgressUpdate(values);
					}

					@Override
					protected void onPostExecute(Boolean result) {
						TraceCompleted("ValOne");
						pbProgress.setVisibility(View.GONE);
						super.onPostExecute(result);
					}
				}.execute("");

			} catch (Exception e) {
				// TODO: handle exception
			}
		}

	}

	public void chVal1ReverseClicked(View v) {
		if (v != null && !Val1Reverse) {
			Val1Reverse = true;
		} else {
			Val1Reverse = false;
		}
	}

	/**
	 * Val 2 Click Events
	 * 
	 * @param v
	 */
	// Event of btnVal2 Clicked
	public void btnVal2Clicked(View v) {
		if (!pbProgress.isShown()) {
			pbProgress.setVisibility(View.VISIBLE);
			ElapsedTimes = new ArrayList<String>();
			try {
				new AsyncTask<String, Integer, Boolean>() {
					@Override
					protected Boolean doInBackground(String... params) {
						for (int i = 1; i <= Val2RepeatTimes; i++) {
							publishProgress(i);
							Val2 runVal2 = new Val2();
							// Start our test and return a value
							MicroTimer time = new MicroTimer();
							runVal2.Start(i, Val2InnerLoop, BufferToTrace);
							ElapsedTimes.add(time.getFinalTime());
						}
						return null;
					}
					
					@Override
					protected void onProgressUpdate(Integer... values) {
						UpdateProgressMessage("ValTwo: "
								+ Integer.toString(values[0]) + "/"
								+ Long.toString(Val2RepeatTimes));
						super.onProgressUpdate(values);
					}

					@Override
					protected void onPostExecute(Boolean result) {
						TraceCompleted("ValTwo");
						pbProgress.setVisibility(View.GONE);
						super.onPostExecute(result);
					}
				}.execute("");

			} catch (Exception e) {
				// TODO: handle exception
			}
		}
	}

	/**
	 * Val 3 Click Events
	 * 
	 * @param v
	 */
	// Event of btnVal3 Clicked
	public void btnVal3Clicked(View v) {
		if (!pbProgress.isShown()) {
			pbProgress.setVisibility(View.VISIBLE);
			ElapsedTimes = new ArrayList<String>();
			try {
				new AsyncTask<String, Integer, Boolean>() {
					@Override
					protected Boolean doInBackground(String... params) {
						for (int i = 1; i <= Val3RepeatTimes; i++) {
							publishProgress(i);
							Val3 runVal3 = new Val3();
							// Start our test and return a value
							MicroTimer time = new MicroTimer();
							runVal3.Start(i, Val3FN1Loop, Val3FN2Loop,
									BufferToTrace);
							ElapsedTimes.add(time.getFinalTime());
						}
						return null;
					}
					
					@Override
					protected void onProgressUpdate(Integer... values) {
						UpdateProgressMessage("ValThree: "
								+ Integer.toString(values[0]) + "/"
								+ Long.toString(Val3RepeatTimes));
						super.onProgressUpdate(values);
					}
					
					@Override
					protected void onPostExecute(Boolean result) {
						TraceCompleted("ValThree");
						pbProgress.setVisibility(View.GONE);
						super.onPostExecute(result);
					}
				}.execute("");

			} catch (Exception e) {
				// TODO: handle exception
			}
		}

	}

	/**
	 * Val 4 Click Events
	 * 
	 * @param v
	 */
	// Event of btnVal4 Clicked
	public void btnVal4Clicked(View v) {
		if (!pbProgress.isShown()) {
			pbProgress.setVisibility(View.VISIBLE);
			ElapsedTimes = new ArrayList<String>();
			try {
				new AsyncTask<String, Integer, Boolean>() {
					@Override
					protected Boolean doInBackground(String... params) {
						for (int i = 1; i <= Val4RepeatTimes; i++) {
							publishProgress(i);
							Val4 runVal4 = new Val4();
							// Start our test and return a value
							MicroTimer time = new MicroTimer();
							runVal4.Start(i, Val4FN1Loop, Val4FN2Loop,
									BufferToTrace);
							ElapsedTimes.add(time.getFinalTime());
						}
						return null;
					}
					@Override
					protected void onProgressUpdate(Integer... values) {
						UpdateProgressMessage("ValFour: "
								+ Integer.toString(values[0]) + "/"
								+ Long.toString(Val4RepeatTimes));
						super.onProgressUpdate(values);
					}
					@Override
					protected void onPostExecute(Boolean result) {
						TraceCompleted("ValFour");
						pbProgress.setVisibility(View.GONE);
						super.onPostExecute(result);
					}
				}.execute("");

			} catch (Exception e) {
				// TODO: handle exception
			}
		}
	}

	/**
	 * Val 5 Click Events
	 * 
	 * @param v
	 */
	// Event of btnVal5 Clicked
	public void btnVal5Clicked(View v) {
		if (!pbProgress.isShown()) {
			pbProgress.setVisibility(View.VISIBLE);
			ElapsedTimes = new ArrayList<String>();
			try {
				new AsyncTask<String, Integer, Boolean>() {
					@Override
					protected Boolean doInBackground(String... params) {
						for (int i = 1; i <= Val5RepeatTimes; i++) {
							publishProgress(i);
							Val5 runVal5 = new Val5();
							// Start our test and return a value
							MicroTimer time = new MicroTimer();
							runVal5.Start(i, Val5FN1Loop, Val5FN2Loop,
									BufferToTrace);
							ElapsedTimes.add(time.getFinalTime());
						}
						return null;
					}
					@Override
					protected void onProgressUpdate(Integer... values) {
						UpdateProgressMessage("ValFive: "
								+ Integer.toString(values[0]) + "/"
								+ Long.toString(Val5RepeatTimes));
						super.onProgressUpdate(values);
					}
					@Override
					protected void onPostExecute(Boolean result) {
						TraceCompleted("ValFive");
						pbProgress.setVisibility(View.GONE);
						super.onPostExecute(result);
					}
				}.execute("");

			} catch (Exception e) {
				// TODO: handle exception
			}
		}
	}

	/**
	 * Val 6 Click Events
	 * 
	 * @param v
	 */
	// Event of btnVal6 Clicked
	public void btnVal6Clicked(View v) {
		if (!pbProgress.isShown()) {
			pbProgress.setVisibility(View.VISIBLE);
			ElapsedTimes = new ArrayList<String>();
			try {
				new AsyncTask<String, Integer, Boolean>() {
					@Override
					protected Boolean doInBackground(String... params) {
						for (int i = 1; i <= Val6RepeatTimes; i++) {
							publishProgress(i);
							Val6 runVal6 = new Val6();
							// Start our test and return a value
							MicroTimer time = new MicroTimer();
							runVal6.Start(i, Val6LeafLoop, Val6EachLoop,
									Val6Depth, BufferToTrace);
							ElapsedTimes.add(time.getFinalTime());							
						}
						return null;
					}
					@Override
					protected void onProgressUpdate(Integer... values) {
						UpdateProgressMessage("ValSix: "
								+ Integer.toString(values[0]) + "/"
								+ Long.toString(Val6RepeatTimes));
						super.onProgressUpdate(values);
					}
					@Override
					protected void onPostExecute(Boolean result) {
						TraceCompleted("ValSix");
						pbProgress.setVisibility(View.GONE);
						super.onPostExecute(result);
					}
				}.execute("");

			} catch (Exception e) {
				// TODO: handle exception
			}
		}
	}

	/**
	 * Misc
	 * 
	 * @param v
	 */

	public void MessageBox(String message) {
		Toast.makeText(this, message, Toast.LENGTH_LONG).show();
	}

	static void UpdateProgressMessage(String Message) {

		tvProgress.setText(Message);
	}

	void TraceCompleted(String TraceName) {
		UpdateProgressMessage(TraceName+": Done!");
		WriteElapsedTimeToSD(ElapsedTimes, TraceName);
		Vibrate();
		MessageBox(TraceName + " trace done!");
		RaiseNotification(
				"AndroidSuite \"" + TraceName + "\" Completed!",
				"Total registered traces: "
						+ Integer.toString(ElapsedTimes.size()));
	}

	public static void DeleteCompleted() {
		pbProgress.setVisibility(View.GONE);
		UpdateProgressMessage("All cleaned!");
	}

	public void Vibrate() {
		Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
		// Vibrate for 50 milliseconds
		v.vibrate(50);
	}

	public void RaiseNotification(String titleNotification,
			String mesgNotification) {
		Intent intent = new Intent(this, NotificationReceiverActivity.class);
		@SuppressWarnings("unused")
		PendingIntent pIntent = PendingIntent.getActivity(this, 0, intent, 0);

		if (Build.VERSION.SDK_INT >= 11) {

			// Build notification
			// Actions are just fake
			Notification noti = new Notification.Builder(this)
					.setContentTitle(titleNotification)
					.setContentText(mesgNotification)
					.setSound(
							RingtoneManager
									.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
					.setStyle(
							new Notification.BigTextStyle()
									.bigText(mesgNotification))
					.setSmallIcon(R.drawable.ic_launcher).build();

			NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);

			// Hide the notification after its selected
			noti.flags |= Notification.FLAG_AUTO_CANCEL;

			notificationManager.notify(0, noti);
		} else {
			NotificationCompat.Builder builder = new NotificationCompat.Builder(
					this)
					.setAutoCancel(true)
					.setContentTitle(titleNotification)
					.setContentText(mesgNotification)
					.setSound(
							RingtoneManager
									.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
					.setSmallIcon(R.drawable.ic_launcher);

			PendingIntent in = PendingIntent.getActivity(
					getApplicationContext(), 0, intent, 0);
			builder.setContentIntent(in);

			NotificationManager notificationManager = null;
			try {
				notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
			} catch (Exception e) {
				Log.e("ERROR", e.getMessage());
			}

			try {
				notificationManager.notify(0, builder.build());
			} catch (Exception e) {
				Log.e("ERROR", e.getMessage());
			}
		}
	}

	void WriteElapsedTimeToSD(List<String> ElapsedTimes, String TraceName) {
		if (MainActivity.ElapsedTimes != null
				&& MainActivity.ElapsedTimes.size() > 0) {
			for (int i = 0; i < MainActivity.ElapsedTimes.size(); i++) {
				AppendToFile(TraceName, MainActivity.ElapsedTimes.get(i));
				Log.d("Writing...", Integer.toString(i + 1) + " elapsed times.");
			}
		}
	}

	void AppendToFile(String TraceName, String Message) {
		File serviceTimesFile = new File(Environment
				.getExternalStorageDirectory().getPath()
				+ "/Traces/"
				+ TraceName
				+ "-ServiceTimes.csv");
		if (!serviceTimesFile.exists()) {
			try {
				serviceTimesFile.createNewFile();
				try {
					// BufferedWriter for performance, true to set append to
					// file flag
					BufferedWriter buf = new BufferedWriter(new FileWriter(
							serviceTimesFile, true));
					buf.append("ServiceTimes");
					buf.newLine();
					buf.append(Message);
					buf.newLine();
					buf.flush();
					buf.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		} else {
			try {
				// BufferedWriter for performance, true to set append to file
				// flag
				BufferedWriter buf = new BufferedWriter(new FileWriter(
						serviceTimesFile, true));
				buf.append(Message);
				buf.newLine();
				buf.flush();
				buf.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
	void WhoAmI()
	{
		Log.e("~", "************************");
		Log.d("*", "Android Suite");
		Log.d("*", "Purpose:	Measure Mobile App Performance");
		Log.d("*", "Built on Eclipse for Linux, Ubuntu 12.04 LTS");
		Log.d("*", "By:	Ramon Luis De Jesus");
		Log.d("*", "On:	May 30, 2013	1:30pm");
		Log.d("*", "Note:	Integer values don't matter much on MainActivity.java");
		Log.d("*", "Values here are set for reference or overwrite actual defaults on val's x.");
		Log.e("~", "************************");			
	}
}
