123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491 |
- 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 org.apache.http.HttpResponse;
- import org.apache.http.client.HttpClient;
- import org.apache.http.client.methods.HttpPost;
- import org.apache.http.entity.StringEntity;
- import de.tudarmstadt.informatik.hostage.R;
- import de.tudarmstadt.informatik.hostage.commons.HelperUtils;
- import de.tudarmstadt.informatik.hostage.logging.Logger;
- import de.tudarmstadt.informatik.hostage.logging.Record;
- import de.tudarmstadt.informatik.hostage.logging.SQLLogger;
- 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;
- /**
- * 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 {
-
- public static final int JSON = 0x01;
-
- private final SimpleDateFormat sdf = new SimpleDateFormat("MMM dd,yyyy HH:mm", Locale.US);
- private Logger logger;
- private SharedPreferences pref;
- private Editor editor;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_viewlog);
- logger = new SQLLogger(this);
- 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.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 = logger.getAllRecords();
- for(Record record : records){
- log.write((record.toString(format) + "\n").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.
- * 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.
- * @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());
- // Create a new Thread for upload
- new Thread(new Runnable() {
- public void run() {
- // Create a https client. Uses MySSLSocketFactory to accept all certificates
- HttpClient httpclient = HelperUtils.createHttpClient();
- // get RecordList
- ArrayList<Record> recordList = logger.getRecordOfEachAttack(lastUploadedAttackId);
- final int progressMax = recordList.size();
- Log.i("SQLLogger", "Logs to upload: " + progressMax);
- HttpPost httppost;
- int progressBarStatus = 0;
- for(Record record: recordList){
- Log.i("SQLLogger", "Uploading log: " + progressBarStatus);
- try {
- // Create HttpPost
- httppost = new HttpPost(pref.getString("pref_upload", "https://ssi.cased.de"));
- // Create JSON String of Record
- StringEntity se = new StringEntity(record.toString(JSON));
- httppost.setEntity(se);
- // Execute HttpPost
- HttpResponse response = httpclient.execute(httppost);
- Log.i("SQLLogger", "Statuscode of log " + progressBarStatus + ": " + " " + response.getStatusLine().getReasonPhrase());
- Log.i("SQLLogger", "Statuscode of log " + progressBarStatus + ": " + " " + response.getStatusLine().getStatusCode());
- // Update Notification progress bar
- progressBarStatus++;
- builder.setProgress(progressMax, progressBarStatus, false);
- // Update the progress bar
- mNotifyManager.notify(2, builder.build());
- } catch (Exception e) {
- Log.i("SQLLogger", "Failed");
- e.printStackTrace();
- }
- }
-
- 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));
- }
- /**
- * Creates a Dialog that lets the user decide which criteria he want to use to delete records.
- * Then calls the corresponding method.
- * @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.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 Logger#deleteByBSSID(String)} to delete all records with the chosen BSSID
- * @see Logger#deleteByBSSID
- */
- private void deleteByBSSID() {
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- final String[] bssidArray = logger.getAllBSSIDS();
- for(int i = 0; i < bssidArray.length; i++){
- bssidArray[i] = bssidArray[i] + " (" + logger.getSSID(bssidArray[i]) +")";
- }
- builder.setTitle(R.string.delete_dialog_title);
- builder.setItems(bssidArray, 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 Logger#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.dialog_clear_database_date)
- .setMessage(sdf.format(calendar.getTime()))
- .setPositiveButton(R.string.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.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 Logger#clearData()
- */
- private void deleteAll() {
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setMessage(R.string.dialog_clear_database)
- .setPositiveButton(R.string.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.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 Logger#getAttackCount()
- * @see Logger#getAttackPerProtokolCount(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.getAttackPerProtokolCount(protocol));
- }
- table.addView(row);
- }
- setFirstAndLastAttack();
- }
- /**
- * Sets the TextViews for first and last attack.
- * @see Logger#getSmallestAttackId()
- * @see Logger#getHighestAttackId()
- * @see Logger#getRecordOfAttackId(long)
- */
- private void setFirstAndLastAttack() {
- Record firstAttack = logger.getRecordOfAttackId(logger.getSmallestAttackId());
- Record lastAttack = 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("-");
- }
- }
- }
|