123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535 |
- package de.tudarmstadt.informatik.hostage.ui;
- import java.io.File;
- import java.io.FileOutputStream;
- import java.text.SimpleDateFormat;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.Calendar;
- import java.util.Date;
- import java.util.Locale;
- import android.annotation.SuppressLint;
- import android.app.Activity;
- import android.app.AlertDialog;
- import android.app.DatePickerDialog;
- import android.app.Dialog;
- import android.app.NotificationManager;
- import android.app.PendingIntent;
- import android.content.Context;
- import android.content.DialogInterface;
- import android.content.Intent;
- import android.content.SharedPreferences;
- import android.content.SharedPreferences.Editor;
- import android.os.Build;
- import android.os.Bundle;
- import android.os.Environment;
- import android.preference.PreferenceManager;
- import android.support.v4.app.NotificationCompat;
- import android.support.v4.app.TaskStackBuilder;
- import android.util.Log;
- import android.view.Gravity;
- import android.view.Menu;
- import android.view.MenuItem;
- import android.view.View;
- import android.widget.DatePicker;
- import android.widget.TableLayout;
- import android.widget.TableRow;
- import android.widget.TextView;
- import android.widget.TimePicker;
- import android.widget.Toast;
- import de.tudarmstadt.informatik.hostage.R;
- import de.tudarmstadt.informatik.hostage.commons.HelperUtils;
- import de.tudarmstadt.informatik.hostage.logging.Record;
- import de.tudarmstadt.informatik.hostage.logging.formatter.TraCINgFormatter;
- /**
- * ViewLog shows Statistics about the recorded Attacks. It also offers the user
- * several options to perform actions with the database. This includes:<br>
- * - show records,<br>
- * - export records,<br>
- * - upload records,<br>
- * - and delete records.
- *
- * @author Lars Pandikow
- */
- public class ViewLog extends Activity {
- private final SimpleDateFormat sdf = new SimpleDateFormat(
- "MMM dd,yyyy HH:mm", Locale.US);
- private SharedPreferences pref;
- private Editor editor;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_viewlog);
- pref = PreferenceManager.getDefaultSharedPreferences(this);
- editor = pref.edit();
- initStatistic();
- }
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- getMenuInflater().inflate(R.menu.main, menu);
- return true;
- }
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- // Handle item selection
- switch (item.getItemId()) {
- case R.id.action_settings:
- startActivity(new Intent(this, SettingsActivity.class));
- break;
- case R.id.action_about:
- startActivity(new Intent(this, AboutActivity.class));
- break;
- default:
- }
- return super.onOptionsItemSelected(item);
- }
- /**
- * Creates a Dialog to choose export format. Then calls
- * {@link ViewLog#exportDatabase(int)}
- *
- * @param view
- * View elements which triggers the method call.
- */
- public void exportDatabase(View view) {
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setTitle(R.string.gui_export_dialog_title);
- builder.setItems(R.array.format, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int position) {
- exportDatabase(position);
- }
- });
- builder.create();
- builder.show();
- }
- /**
- * Exports all records in a given format. Before exporting checks export
- * location from preferences.
- *
- * @param format
- * Integer coded export format
- * @see Record#toString(int)
- */
- private void exportDatabase(int format) {
- try {
- FileOutputStream log;
- String filename = "hostage_" + format + "_"
- + System.currentTimeMillis() + ".log";
- boolean externalStorage = pref.getBoolean("pref_external_storage",
- false);
- String externalLocation = pref.getString("pref_external_location",
- "");
- if (externalStorage) {
- String root = Environment.getExternalStorageDirectory()
- .toString();
- if (root != null && HelperUtils.isExternalStorageWritable()) {
- File dir = new File(root + externalLocation);
- dir.mkdirs();
- File file = new File(dir, filename);
- log = new FileOutputStream(file);
- } else {
- Toast.makeText(this, "Could not write to SD Card",
- Toast.LENGTH_SHORT).show();
- return;
- }
- } else {
- log = this.openFileOutput(
- "hostage_" + format + "_" + System.currentTimeMillis()
- + ".log", Context.MODE_PRIVATE);
- }
- ArrayList<Record> records = null;// logger.getAllRecords();
- for (Record record : records) {
- log.write((record.toString((format == 1) ? TraCINgFormatter
- .getInstance() : null)).getBytes());
- }
- log.flush();
- log.close();
- Toast.makeText(
- this,
- externalStorage ? filename + " saved on external memory! "
- + externalLocation : filename
- + " saved on internal memory!", Toast.LENGTH_LONG)
- .show();
- } catch (Exception e) {
- Toast.makeText(this, "Could not write to SD Card",
- Toast.LENGTH_SHORT).show();
- e.printStackTrace();
- }
- }
- /**
- * Uploads a JSON Representation of each attack to a server, specified in
- * the preferences.<br>
- * The method only uploads information about attacks that have net been
- * uploaded yet.<br>
- * The local and remote IP of each record will be replaced with the external
- * IP of then device at the time of the upload. For the Upload it uses a
- * HttpPost with a HttpsClient, which does not validate any certificates.<br>
- * The Upload runs in its own Thread.<br>
- * While uploading the method also creates a notification to inform the user
- * about the status of the upload.<br>
- * <b>Only uploads Records with a external IP that is not null!
- *
- * @param view
- * View elements which triggers the method call.
- * @see de.tudarmstadt.informatik.hostage.net.MySSLSocketFactory
- */
- public void uploadDatabase(View view) {
- // Create a Notification
- final NotificationCompat.Builder builder;
- final NotificationManager mNotifyManager;
- final int lastUploadedAttackId = pref.getInt("LAST_UPLOADED_ATTACK_ID",
- -1);
- int currentAttackId = pref.getInt("ATTACK_ID_COUNTER", 0);
- // Check if there are new records to upload
- if (lastUploadedAttackId == currentAttackId - 1) {
- // Inform user that no upload is necessary
- Toast.makeText(this, "All data have already been uploaded.",
- Toast.LENGTH_SHORT).show();
- return;
- }
- // Build and show Upload Notification in notification bar
- builder = new NotificationCompat.Builder(this)
- .setContentTitle(this.getString(R.string.app_name))
- .setContentText("Upload in progress...")
- .setTicker("Uploading Data...")
- .setSmallIcon(R.drawable.ic_launcher)
- .setWhen(System.currentTimeMillis());
- TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
- stackBuilder.addParentStack(MainActivity.class);
- stackBuilder.addNextIntent(new Intent());
- PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0,
- PendingIntent.FLAG_UPDATE_CURRENT);
- builder.setContentIntent(resultPendingIntent);
- builder.setAutoCancel(true);
- builder.setOnlyAlertOnce(false);
- mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
- mNotifyManager.notify(2, builder.build());
- final Context context = this;
- // Create a new Thread for upload
- new Thread(new Runnable() {
- public void run() {
- // get RecordList
- ArrayList<Record> recordList = null;// logger.getRecordOfEachAttack(lastUploadedAttackId);
- final int progressMax = recordList.size();
- Log.i("SQLLogger", "Logs to upload: " + progressMax);
- int progressBarStatus = 0;
- int retry_counter = 0;
- while (progressBarStatus < progressMax) {
- Record record = recordList.get(progressBarStatus);
- // Only upload records with a saved external ip
- if (record.getExternalIP() != null) {
- retry_counter = 0;
- if (HelperUtils.uploadSingleRecord(context, record)) {
- // Update Notification progress bar
- progressBarStatus++;
- builder.setProgress(progressMax, progressBarStatus,
- false);
- // Update the progress bar
- mNotifyManager.notify(2, builder.build());
- } else {
- retry_counter++;
- if (retry_counter == 3) {
- retry_counter = 0;
- progressBarStatus++;
- }
- }
- }
- }
- if (progressBarStatus == progressMax) {
- // When the loop is finished, updates the notification
- builder.setContentText("Upload complete")
- .setTicker("Upload complete")
- // Removes the progress bar
- .setProgress(0, 0, false);
- mNotifyManager.notify(2, builder.build());
- }
- }
- }).start();
- editor.putInt("LAST_UPLOADED_ATTACK_ID", currentAttackId - 1);
- editor.commit();
- }
- /**
- * Starts a ViewLogTable Activity.
- *
- * @param view
- * View elements which triggers the method call.
- * @see ViewLogTable
- */
- public void showLog(View view) {
- startActivity(new Intent(this, ViewLogTable.class));
- // TODO Delete
- }
- /**
- * Creates a Dialog that lets the user decide which criteria he want to use
- * to delete records. Then calls the corresponding method.<br>
- * The possible criteria are coded in /res/values/arrays.xml To add a
- * criteria add a String to the array and extend the switch statement.
- *
- * @param view
- * View elements which triggers the method call.
- * @see ViewLog#deleteByBSSID()
- * @see ViewLog#deleteByDate()
- * @see ViewLog#deleteAll()
- */
- public void deleteLog(View view) {
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setTitle(R.string.gui_delete_dialog_title);
- builder.setItems(R.array.delete_criteria,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int position) {
- switch (position) {
- case 0:
- deleteByBSSID();
- break;
- case 1:
- deleteByDate();
- break;
- case 2:
- deleteAll();
- }
- }
- });
- builder.create();
- builder.show();
- }
- /**
- * Shows a List with all recorded BSSIDs. If a BSSID is selected the method
- * calls {@link ILogger#deleteByBSSID(String)} to delete all records with
- * the chosen BSSID
- *
- * @see ILogger#deleteByBSSID
- */
- private void deleteByBSSID() {
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- final String[] bssidArray = null;// logger.getAllBSSIDS();
- final String[] strings = new String[bssidArray.length];
- for (int i = 0; i < bssidArray.length; i++) {
- strings[i] = bssidArray[i] + " (" // + logger.getSSID(bssidArray[i])
- + ")";
- }
- builder.setTitle(R.string.gui_delete_dialog_title);
- builder.setItems(strings, new DialogInterface.OnClickListener() {
- @SuppressLint("NewApi")
- public void onClick(DialogInterface dialog, int position) {
- // logger.deleteByBSSID(bssidArray[position]);
- Toast.makeText(
- getApplicationContext(),
- "All entries with bssid '" + bssidArray[position]
- + "' deleted.", Toast.LENGTH_SHORT).show();
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
- recreate();
- } else {
- Intent intent = getIntent();
- finish();
- startActivity(intent);
- }
- }
- });
- builder.create();
- builder.show();
- }
- /**
- * Creates a DatePicking Dialog where the user can choose a date. Afterwards
- * {@link ViewLog#deleteByDate(int, int, int)} is called.
- */
- private void deleteByDate() {
- showDialog(0);
- }
- @Override
- protected Dialog onCreateDialog(int id) {
- switch (id) {
- case 0:
- final Calendar cal = Calendar.getInstance();
- int pYear = cal.get(Calendar.YEAR);
- int pMonth = cal.get(Calendar.MONTH);
- int pDay = cal.get(Calendar.DAY_OF_MONTH);
- return new DatePickerDialog(this,
- new DatePickerDialog.OnDateSetListener() {
- public void onDateSet(DatePicker view, int year,
- int monthOfYear, int dayOfMonth) {
- deleteByDate(year, monthOfYear, dayOfMonth);
- }
- }, pYear, pMonth, pDay);
- }
- return null;
- }
- /**
- * Shows a Dialog with the given date and ask him to confirm deleting
- * records that are older than the shown date. When the user confirms
- * {@link ILogger#deleteByDate(long)} is called with a long representation
- * of the Date. If the user cancels the Dialog nothing happens and the
- * dialog disappears.
- *
- * @param year
- * @param monthOfYear
- * @param dayOfMonth
- */
- private void deleteByDate(int year, int monthOfYear, int dayOfMonth) {
- TimePicker timePicker = new TimePicker(this);
- final Calendar calendar = Calendar.getInstance();
- calendar.set(year, monthOfYear, dayOfMonth,
- timePicker.getCurrentHour(), timePicker.getCurrentMinute(), 0);
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setTitle(R.string.gui_dialog_clear_database_date)
- .setMessage(sdf.format(calendar.getTime()))
- .setPositiveButton(R.string.gui_delete,
- new DialogInterface.OnClickListener() {
- @SuppressLint("NewApi")
- public void onClick(DialogInterface dialog, int id) {
- long time = calendar.getTimeInMillis();
- // Delete Data
- // logger.deleteByDate(time);
- Toast.makeText(getApplicationContext(),
- "Data sets deleted!",
- Toast.LENGTH_SHORT).show();
- // Recreate the activity
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
- recreate();
- } else {
- Intent intent = getIntent();
- finish();
- startActivity(intent);
- }
- }
- })
- .setNegativeButton(R.string.gui_cancel,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
- // User cancelled the dialog
- }
- });
- // Create the AlertDialog object
- builder.create();
- builder.show();
- }
- /**
- * Shows a Dialog to confirm that the database should be cleared. If
- * confirmed {@link SQLLogger#clearData()} is called.
- *
- * @see ILogger#clearData()
- */
- private void deleteAll() {
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setMessage(R.string.gui_dialog_clear_database)
- .setPositiveButton(R.string.gui_clear,
- new DialogInterface.OnClickListener() {
- @SuppressLint("NewApi")
- public void onClick(DialogInterface dialog, int id) {
- // Clear all Data
- // logger.clearData();
- editor.putInt("ATTACK_ID_COUNTER", 0);
- editor.putInt("LAST_UPLOADED_ATTACK_ID", -1);
- editor.commit();
- Toast.makeText(getApplicationContext(),
- "Database cleared!", Toast.LENGTH_SHORT)
- .show();
- // Recreate the activity
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
- recreate();
- } else {
- Intent intent = getIntent();
- finish();
- startActivity(intent);
- }
- }
- })
- .setNegativeButton(R.string.gui_cancel,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
- // User cancelled the dialog
- }
- });
- // Create the AlertDialog object
- builder.create();
- builder.show();
- }
- /**
- * Initializes the Statistics. Creates a table row for every protocol and
- * checks the dabase for the attack count. Calls
- * {@link ViewLog#setFirstAndLastAttack()} to set the TextViews.
- *
- * @see ILogger#getAttackCount()
- * @see ILogger#getAttackPerProtocolCount(String)
- */
- private void initStatistic() {
- TableLayout table = (TableLayout) findViewById(R.id.layoutContainer);
- ArrayList<String> protocols = new ArrayList<String>();
- protocols.add("Total");
- protocols.addAll(Arrays.asList(getResources().getStringArray(
- R.array.protocols)));
- for (String protocol : protocols) {
- TableRow row = new TableRow(this);
- TextView protocolName = new TextView(this);
- protocolName.setBackgroundResource(R.color.dark_grey);
- protocolName.setText(protocol);
- protocolName.setTextAppearance(this,
- android.R.style.TextAppearance_Medium);
- protocolName.setPadding(6, 0, 0, 0);
- row.addView(protocolName);
- TextView value = new TextView(this);
- value.setBackgroundResource(R.color.light_grey);
- value.setTextAppearance(this, android.R.style.TextAppearance_Medium);
- value.setGravity(Gravity.RIGHT);
- value.setPadding(3, 0, 3, 0);
- row.addView(value);
- if (protocol.equals("Total")) {
- value.setText(""); // + logger.getAttackCount());
- } else {
- value.setText("");// +
- // logger.getAttackPerProtocolCount(protocol));
- }
- table.addView(row);
- }
- setFirstAndLastAttack();
- }
- /**
- * Sets the TextViews for first and last attack.
- *
- * @see ILogger#getSmallestAttackId()
- * @see ILogger#getHighestAttackId()
- * @see ILogger#getRecordOfAttackId(long)
- */
- private void setFirstAndLastAttack() {
- Record firstAttack = null;// logger.getRecordOfAttackId(logger.getSmallestAttackId());
- Record lastAttack = null;// logger.getRecordOfAttackId(logger.getHighestAttackId());
- if (firstAttack != null) {
- Date resultdate = new Date(firstAttack.getTimestamp());
- TextView text = (TextView) findViewById(R.id.textFirstAttackValue);
- text.setText(sdf.format(resultdate));
- text = (TextView) findViewById(R.id.textLastAttackValue);
- resultdate = new Date(lastAttack.getTimestamp());
- text.setText(sdf.format(resultdate));
- } else {
- TextView text = (TextView) findViewById(R.id.textFirstAttackValue);
- text.setText("-");
- text = (TextView) findViewById(R.id.textLastAttackValue);
- text.setText("-");
- }
- }
- }
|