Browse Source

moved ui2 to ui

Alexander Brakowski 9 years ago
parent
commit
ec2b93d28e
41 changed files with 10562 additions and 0 deletions
  1. 751 0
      src/de/tudarmstadt/informatik/hostage/ui/activity/MainActivity.java
  2. 40 0
      src/de/tudarmstadt/informatik/hostage/ui/activity/ProfileEditActivity.java
  3. 64 0
      src/de/tudarmstadt/informatik/hostage/ui/adapter/DrawerListAdapter.java
  4. 152 0
      src/de/tudarmstadt/informatik/hostage/ui/adapter/ExpandableListAdapter.java
  5. 235 0
      src/de/tudarmstadt/informatik/hostage/ui/adapter/ProfileManagerListAdapter.java
  6. 64 0
      src/de/tudarmstadt/informatik/hostage/ui/adapter/RecordListAdapter.java
  7. 314 0
      src/de/tudarmstadt/informatik/hostage/ui/adapter/ServicesListAdapter.java
  8. 121 0
      src/de/tudarmstadt/informatik/hostage/ui/adapter/StatisticListAdapter.java
  9. 199 0
      src/de/tudarmstadt/informatik/hostage/ui/dialog/ChecklistDialog.java
  10. 303 0
      src/de/tudarmstadt/informatik/hostage/ui/dialog/DateTimeDialogFragment.java
  11. 52 0
      src/de/tudarmstadt/informatik/hostage/ui/fragment/AboutFragment.java
  12. 85 0
      src/de/tudarmstadt/informatik/hostage/ui/fragment/ConnectionInfoDialogFragment.java
  13. 543 0
      src/de/tudarmstadt/informatik/hostage/ui/fragment/HomeFragment.java
  14. 118 0
      src/de/tudarmstadt/informatik/hostage/ui/fragment/PreferenceHostageFrament.java
  15. 320 0
      src/de/tudarmstadt/informatik/hostage/ui/fragment/ProfileEditFragment.java
  16. 154 0
      src/de/tudarmstadt/informatik/hostage/ui/fragment/ProfileManagerFragment.java
  17. 246 0
      src/de/tudarmstadt/informatik/hostage/ui/fragment/RecordDetailFragment.java
  18. 1438 0
      src/de/tudarmstadt/informatik/hostage/ui/fragment/RecordOverviewFragment.java
  19. 322 0
      src/de/tudarmstadt/informatik/hostage/ui/fragment/ServicesFragment.java
  20. 283 0
      src/de/tudarmstadt/informatik/hostage/ui/fragment/SettingsFragment.java
  21. 1846 0
      src/de/tudarmstadt/informatik/hostage/ui/fragment/StatisticsFragment.java
  22. 428 0
      src/de/tudarmstadt/informatik/hostage/ui/fragment/ThreatMapFragment.java
  23. 35 0
      src/de/tudarmstadt/informatik/hostage/ui/fragment/TrackerFragment.java
  24. 66 0
      src/de/tudarmstadt/informatik/hostage/ui/fragment/UpNavigatibleFragment.java
  25. 380 0
      src/de/tudarmstadt/informatik/hostage/ui/fragment/opengl/AnimatedMesh.java
  26. 41 0
      src/de/tudarmstadt/informatik/hostage/ui/fragment/opengl/HomeGLSurfaceView.java
  27. 70 0
      src/de/tudarmstadt/informatik/hostage/ui/fragment/opengl/Quaternion.java
  28. 359 0
      src/de/tudarmstadt/informatik/hostage/ui/fragment/opengl/ThreatIndicatorGLRenderer.java
  29. 26 0
      src/de/tudarmstadt/informatik/hostage/ui/helper/ColorSequenceGenerator.java
  30. 337 0
      src/de/tudarmstadt/informatik/hostage/ui/layouts/FlowLayout.java
  31. 28 0
      src/de/tudarmstadt/informatik/hostage/ui/model/DrawerListItem.java
  32. 41 0
      src/de/tudarmstadt/informatik/hostage/ui/model/ExpandableListItem.java
  33. 366 0
      src/de/tudarmstadt/informatik/hostage/ui/model/LogFilter.java
  34. 49 0
      src/de/tudarmstadt/informatik/hostage/ui/model/PlotComparisonItem.java
  35. 24 0
      src/de/tudarmstadt/informatik/hostage/ui/model/ServicesListItem.java
  36. 200 0
      src/de/tudarmstadt/informatik/hostage/ui/popup/AbstractPopup.java
  37. 133 0
      src/de/tudarmstadt/informatik/hostage/ui/popup/AbstractPopupItem.java
  38. 86 0
      src/de/tudarmstadt/informatik/hostage/ui/popup/SimplePopupItem.java
  39. 58 0
      src/de/tudarmstadt/informatik/hostage/ui/popup/SimplePopupTable.java
  40. 133 0
      src/de/tudarmstadt/informatik/hostage/ui/popup/SplitPopupItem.java
  41. 52 0
      src/de/tudarmstadt/informatik/hostage/ui/swipelist/SwipeListView.java

+ 751 - 0
src/de/tudarmstadt/informatik/hostage/ui/activity/MainActivity.java

@@ -0,0 +1,751 @@
+package de.tudarmstadt.informatik.hostage.ui2.activity;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import android.app.ActionBar;
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.AlertDialog;
+import android.app.Fragment;
+import android.app.FragmentManager;
+import android.app.FragmentTransaction;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.SharedPreferences;
+import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
+import android.content.res.TypedArray;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.support.v4.app.ActionBarDrawerToggle;
+import android.support.v4.widget.DrawerLayout;
+import android.text.Html;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.KeyEvent;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.ListView;
+import android.widget.Toast;
+
+import de.tudarmstadt.informatik.hostage.Hostage;
+import de.tudarmstadt.informatik.hostage.R;
+import de.tudarmstadt.informatik.hostage.model.Profile;
+import de.tudarmstadt.informatik.hostage.persistence.ProfileManager;
+import de.tudarmstadt.informatik.hostage.ui2.model.LogFilter;
+import de.tudarmstadt.informatik.hostage.ui2.adapter.DrawerListAdapter;
+import de.tudarmstadt.informatik.hostage.ui2.fragment.AboutFragment;
+import de.tudarmstadt.informatik.hostage.ui2.fragment.HomeFragment;
+import de.tudarmstadt.informatik.hostage.ui2.fragment.ProfileManagerFragment;
+import de.tudarmstadt.informatik.hostage.ui2.fragment.RecordOverviewFragment;
+import de.tudarmstadt.informatik.hostage.ui2.fragment.ServicesFragment;
+import de.tudarmstadt.informatik.hostage.ui2.fragment.SettingsFragment;
+import de.tudarmstadt.informatik.hostage.ui2.fragment.StatisticsFragment;
+import de.tudarmstadt.informatik.hostage.ui2.fragment.ThreatMapFragment;
+import de.tudarmstadt.informatik.hostage.ui2.fragment.UpNavigatibleFragment;
+import de.tudarmstadt.informatik.hostage.ui2.fragment.opengl.ThreatIndicatorGLRenderer;
+import de.tudarmstadt.informatik.hostage.ui2.model.DrawerListItem;
+
+/**
+ * Manages the whole application, and should act like an singleton.
+ *
+ * @author Alexander Brakowski
+ * @created 12.01.14 23:24
+ */
+public class MainActivity extends Activity {
+	public static volatile Context context;
+
+	/** singleton instance of the MainActivity **/
+	private static MainActivity sInstance = null;
+
+	/**
+	 * The currently displayed fragment
+	 */
+	public Fragment mDisplayedFragment;
+
+	/**
+	 * Holds the Hostage Service
+	 */
+	public Hostage mHoneyService;
+
+	/**
+	 * Manages the navigation drawer
+	 */
+	private DrawerLayout mDrawerLayout;
+
+	/**
+	 * Contains the listview to be displayed in the navigation drawer
+	 */
+	private ListView mDrawerList;
+
+	/**
+	 * Holds the toggler for the navigation drawer in the action bar
+	 */
+	private ActionBarDrawerToggle mDrawerToggle;
+
+	/**
+	 * The text that should be displayed in the drawer toggle
+	 */
+	private CharSequence mDrawerTitle;
+
+	/**
+	 * The text that should be displayed in the action bar
+	 */
+	private CharSequence mTitle;
+
+	/**
+	 * Holds the list, that should be displayed in the listview of the navigation drawer
+	 */
+	private ArrayList<DrawerListItem> mDrawerItems;
+
+	/**
+	 * Hold the state of the Hostage service
+	 */
+	private boolean mServiceBound = false;
+
+	/**
+	 * Connection to bind the background service
+	 *
+	 * @see de.tudarmstadt.informatik.hostage.Hostage
+	 */
+	private ServiceConnection mConnection = new ServiceConnection() {
+		/**
+		 * After the service is bound, check which has been clicked and start
+		 * it.
+		 *
+		 * @see android.content.ServiceConnection#onServiceConnected(android.content.ComponentName,
+		 *      android.os.IBinder)
+		 */
+		@Override
+		public void onServiceConnected(ComponentName name, IBinder service) {
+			mHoneyService = ((Hostage.LocalBinder) service).getService();
+			mServiceBound = true;
+		}
+
+		/**
+		 * After the service is unbound, delete reference.
+		 *
+		 * @see android.content.ServiceConnection#onServiceDisconnected(android.content.ComponentName)
+		 */
+		@Override
+		public void onServiceDisconnected(ComponentName name) {
+			mHoneyService = null;
+			mServiceBound = false;
+		}
+
+	};
+
+	/**
+	 * Holds an profile manager instance
+	 */
+	private ProfileManager mProfileManager;
+
+	/**
+	 * Holds the root fragment for our hierarchical fragment navigation
+	 */
+	private Fragment mRootFragment;
+
+	/**
+	 * Indicates if the warning, that the application will be closed, when pressing back again
+	 */
+	private boolean mCloseWarning = false;
+
+	/**
+	 * Hold the shared preferences for the app
+	 */
+	private SharedPreferences mSharedPreferences;
+
+	/**
+	 * Retrieve the singleton latest instance of the activity
+	 *
+	 * @return MainActivity - the singleton instance
+	 */
+	public static MainActivity getInstance() {
+		return sInstance;
+	}
+
+	/**
+	 * Retrieves the context of the application
+	 *
+	 * @return the context
+	 */
+	public static Context getContext() {
+		return MainActivity.context;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void onStart() {
+		super.onStart();
+
+		if (isServiceRunning()) {
+			this.bindService();
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void onStop() {
+		this.unbindService();
+		super.onStop();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	protected void onCreate(Bundle savedInstanceState) {
+		super.onCreate(savedInstanceState);
+
+		// make the main activity an singleton
+		sInstance = this;
+
+		// sets the static context reference to the application context
+		MainActivity.context = getApplicationContext();
+
+		setContentView(R.layout.activity_drawer_main);
+		mProfileManager = ProfileManager.getInstance();
+
+		// init threat indicator animation
+		ThreatIndicatorGLRenderer.assets = getAssets();
+		ThreatIndicatorGLRenderer.setThreatLevel(ThreatIndicatorGLRenderer.ThreatLevel.NOT_MONITORING);
+
+		// set background color
+		TypedArray arr = getTheme().obtainStyledAttributes(new int[] { android.R.color.background_light });
+		ThreatIndicatorGLRenderer.setBackgroundColor(arr.getColor(0, 0xFFFFFF));
+		arr.recycle();
+
+		// configures the action bar
+		ActionBar actionBar = getActionBar();
+		actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_TITLE | ActionBar.DISPLAY_SHOW_HOME | ActionBar.DISPLAY_HOME_AS_UP);
+		actionBar.setDisplayHomeAsUpEnabled(true);
+		actionBar.setHomeButtonEnabled(true);
+		actionBar.setDisplayShowHomeEnabled(true);
+
+		// sets the drawer and action title to the application title
+		mTitle = mDrawerTitle = getTitle();
+		mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
+		mDrawerList = (ListView) findViewById(R.id.left_drawer);
+
+		// propagates the navigation drawer with items
+		mDrawerItems = new ArrayList<DrawerListItem>();
+		mDrawerItems.add(new DrawerListItem(R.string.drawer_overview, R.drawable.ic_menu_home));
+		mDrawerItems.add(new DrawerListItem(R.string.drawer_threat_map, R.drawable.ic_menu_mapmode));
+		mDrawerItems.add(new DrawerListItem(R.string.drawer_records, R.drawable.ic_menu_records));
+		mDrawerItems.add(new DrawerListItem(R.string.drawer_statistics, R.drawable.ic_menu_stats));
+		mDrawerItems.add(new DrawerListItem(R.string.drawer_services, R.drawable.ic_menu_set_as));
+		mDrawerItems.add(new DrawerListItem(R.string.drawer_profile_manager, R.drawable.ic_menu_allfriends));
+		mDrawerItems.add(new DrawerListItem(R.string.drawer_settings, R.drawable.ic_menu_preferences));
+		mDrawerItems.add(new DrawerListItem(R.string.drawer_help, R.drawable.ic_menu_help));
+		mDrawerItems.add(new DrawerListItem(R.string.drawer_app_info, R.drawable.ic_menu_info_details));
+
+		DrawerListAdapter listAdapter = new DrawerListAdapter(this, mDrawerItems);
+
+		mDrawerList.setAdapter(listAdapter);
+		mDrawerList.setOnItemClickListener(new DrawerItemClickListener());
+
+		// configures the navigation drawer
+		mDrawerToggle = new ActionBarDrawerToggle(this, /* host Activity */
+			mDrawerLayout, /* DrawerLayout object */
+			R.drawable.ic_navigation_drawer, /*
+											 * nav drawer image to replace 'Up'
+											 * caret
+											 */
+			R.string.drawer_open, /* "open drawer" description for accessibility */
+			R.string.drawer_close /* "close drawer" description for accessibility */
+		) {
+			public void onDrawerClosed(View view) {
+				getActionBar().setTitle(mTitle);
+				invalidateOptionsMenu(); // creates call to
+											// onPrepareOptionsMenu()
+			}
+
+			public void onDrawerOpened(View drawerView) {
+				getActionBar().setTitle(mDrawerTitle);
+				invalidateOptionsMenu(); // creates call to
+											// onPrepareOptionsMenu()
+			}
+		};
+
+		mDrawerLayout.setDrawerListener(mDrawerToggle);
+
+		// start the hostage service
+		startAndBind();
+
+		mSharedPreferences = getSharedPreferences(getString(R.string.shared_preference_path), Hostage.MODE_PRIVATE);
+
+
+		if(mSharedPreferences.getBoolean("isFirstRun", true)){
+
+			// opens navigation drawer if first run
+			mDrawerLayout.postDelayed(new Runnable() {
+				@Override
+				public void run() {
+					mDrawerLayout.openDrawer(Gravity.LEFT);
+				}
+			}, 1000);
+
+			onFirstRun();
+		}
+
+
+		if (savedInstanceState == null) {
+			// on first time display view for first nav item
+			displayView(0);
+		}
+	}
+
+	/**
+	 * Displays the disclaimer on first run of the application
+	 */
+	private void onFirstRun(){
+		AlertDialog.Builder builder = new AlertDialog.Builder(this);
+		builder.setMessage(Html.fromHtml(getString(R.string.hostage_disclaimer)))
+				.setCancelable(false)
+				.setPositiveButton(getString(R.string.agree), new DialogInterface.OnClickListener() {
+					public void onClick(DialogInterface dialog, int id) {
+						// and, if the user accept, you can execute something like this:
+						// We need an Editor object to make preference changes.
+						// All objects are from android.context.Context
+						SharedPreferences.Editor editor = mSharedPreferences.edit();
+						editor.putBoolean("isFirstRun", false);
+						// Commit the edits!
+						editor.commit();
+
+                        // Enabled shared preferences for 'first' time non-portbinder activation
+                        SharedPreferences.Editor editor1= mSharedPreferences.edit();
+                        editor1.putBoolean("isFirstEmulation", true);
+                        editor1.commit();
+					}
+				})
+				.setNegativeButton(getString(R.string.disagree), new DialogInterface.OnClickListener() {
+					public void onClick(DialogInterface dialog, int id) {
+						getHostageService().stopListeners();
+						stopAndUnbind();
+						finish();
+					}
+				});
+		AlertDialog alert = builder.create();
+		alert.show();
+	}
+
+	/**
+	 * Starts the hostage service and binds this activity to the service
+	 */
+	public void startAndBind() {
+		if (!isServiceRunning()) {
+			startService(getServiceIntent());
+		}
+
+		bindService();
+	}
+
+	/**
+	 * Stops the hostage service and unbinds from the service
+	 */
+	public void stopAndUnbind() {
+		if (mHoneyService != null) {
+			unbindService();
+		}
+
+		stopService(getServiceIntent());
+	}
+
+	/**
+	 * Unbindes the activity from the service
+	 */
+	public void unbindService() {
+		try {
+			unbindService(mConnection);
+		} catch (IllegalArgumentException ex) {
+			// somehow already unbound.
+		}
+	}
+
+	/**
+	 * Binds the activity to the service
+	 */
+	public void bindService() {
+		bindService(getServiceIntent(), mConnection, BIND_AUTO_CREATE);
+		// mServiceBound = true;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	protected void onDestroy() {
+		super.onDestroy();
+
+		// Unbind running service
+		if (!mHoneyService.hasRunningListeners()) {
+			stopAndUnbind();
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public boolean onOptionsItemSelected(MenuItem item) {
+		// toggle nav drawer on selecting action bar app icon/title
+		if (mDrawerToggle.onOptionsItemSelected(item)) {
+			return true;
+		}
+
+		if (item.getItemId() == android.R.id.home) {
+			if (!mDrawerToggle.isDrawerIndicatorEnabled()) {
+				navigateBack();
+			}
+		}
+
+		return super.onOptionsItemSelected(item);
+	}
+
+	/**
+	 * Navigates up to the parent fragment of the current fragment
+	 */
+	public void navigateBack(){
+		if (!(this.mDisplayedFragment instanceof UpNavigatibleFragment)) {
+			mDrawerToggle.setDrawerIndicatorEnabled(true);
+			return;
+		}
+
+		UpNavigatibleFragment upNav = (UpNavigatibleFragment) this.mDisplayedFragment;
+
+		getFragmentManager().popBackStackImmediate(upNav.getUpFragment().getName(), 0);
+		this.mDisplayedFragment = getFragmentManager().findFragmentById(R.id.content_frame);
+		configureFragment();
+
+		if (!(this.mDisplayedFragment instanceof UpNavigatibleFragment) || !((UpNavigatibleFragment) this.mDisplayedFragment).isUpNavigatible()) {
+			mDrawerToggle.setDrawerIndicatorEnabled(true);
+		} else {
+			mDrawerToggle.setDrawerIndicatorEnabled(false);
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void setTitle(CharSequence title) {
+		mTitle = title;
+		getActionBar().setTitle(mTitle);
+	}
+
+	/**
+	 * When using the ActionBarDrawerToggle, you must call it during
+	 * onPostCreate() and onConfigurationChanged()...
+	 */
+	@Override
+	protected void onPostCreate(Bundle savedInstanceState) {
+		super.onPostCreate(savedInstanceState);
+		// Sync the toggle state after onRestoreInstanceState has occurred.
+		mDrawerToggle.syncState();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void onConfigurationChanged(Configuration newConfig) {
+		super.onConfigurationChanged(newConfig);
+		// Pass any configuration change to the drawer toggls
+		mDrawerToggle.onConfigurationChanged(newConfig);
+	}
+
+	/**
+	 * Displays the view for the given navigation index
+	 *
+	 * @param position the index of the navigation item
+	 */
+	public void displayView(int position) {
+		MainMenuItem menuItemPosition = MainMenuItem.create(position);
+
+		// close the drawer if the to be displayed fragment is already being displayed
+		if (this.mDisplayedFragment != null && this.mDisplayedFragment.getClass() == menuItemPosition.getKlass()) {
+			mDrawerLayout.closeDrawer(mDrawerList);
+			return;
+		}
+
+		// open help video list when pressing help navigation item
+		if(menuItemPosition == MainMenuItem.HELP){
+			Intent intent = new Intent(Intent.ACTION_VIEW);
+			intent.setData(Uri.parse("https://www.youtube.com/playlist?list=PLJyUmtMldh3s1XtRfE4YFaQ8ME7xjf7Gx"));
+			startActivity(intent);
+
+			return;
+		}
+
+		Fragment fragment = null;
+
+		try {
+			fragment = (Fragment) menuItemPosition.getKlass().newInstance();
+		} catch (InstantiationException e) {
+			Log.i(menuItemPosition.getKlass().toString(), "Could not create new instance of fragment");
+		} catch (IllegalAccessException e) {
+			Log.i(menuItemPosition.getKlass().toString(), "Could not create new instance of fragment");
+		}
+
+		if (fragment != null) {
+			if(position == 0 && mRootFragment == null){
+				mRootFragment = fragment;
+			}
+
+			injectFragment(fragment);
+
+			mDrawerList.setItemChecked(position, true);
+			mDrawerList.setSelection(position);
+			setTitle(mDrawerItems.get(position).text);
+		}
+
+		mDrawerLayout.closeDrawer(mDrawerList);
+	}
+
+	/**
+	 * Injects an given fragment into the application content view
+	 *
+	 * @param fragment the fragment to inject
+	 */
+	public void injectFragment(Fragment fragment) {
+		this.mCloseWarning = false;
+
+		// set the action bar up navigation according to the nature of the given fragment
+		if (fragment instanceof UpNavigatibleFragment) {
+			UpNavigatibleFragment upFrag = (UpNavigatibleFragment) fragment;
+			if (upFrag.getUpFragment() == null) {
+				upFrag.setUpFragment(this.mDisplayedFragment.getClass());
+			}
+			if (upFrag.isUpNavigatible()) {
+				mDrawerToggle.setDrawerIndicatorEnabled(false);
+			}
+		}
+
+		configureFragment(fragment);
+
+		// exchange the existing fragment with the given one
+		FragmentManager fragmentManager = getFragmentManager();
+		FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
+		fragmentTransaction.replace(R.id.content_frame, fragment, fragment.getClass().getName());
+		fragmentTransaction.addToBackStack(fragment.getClass().getName());
+
+		fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
+		fragmentTransaction.commit();
+
+		this.mDisplayedFragment = fragment;
+	}
+
+
+	private void configureFragment() {
+		configureFragment(this.mDisplayedFragment);
+	}
+
+	/**
+	 * Configures the given fragment, e.g. fixing the screen orientation
+	 *
+	 * @param fragment the fragment to configure
+	 */
+	private void configureFragment(Fragment fragment) {
+		if (fragment == null)
+			return;
+
+		if (fragment instanceof HomeFragment || fragment instanceof AboutFragment) {
+			setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT | ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
+		} else {
+			setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
+		}
+
+		if (fragment instanceof StatisticsFragment || fragment instanceof RecordOverviewFragment) {
+
+			Intent intent = this.getIntent();
+			intent.removeExtra(LogFilter.LOG_FILTER_INTENT_KEY);
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void onBackPressed() {
+		if (mDisplayedFragment instanceof HomeFragment) {
+
+			if (this.mCloseWarning) {
+				MainActivity.getInstance().getHostageService().stopListeners();
+				MainActivity.getInstance().stopAndUnbind();
+				this.mCloseWarning = false;
+				finish();
+			} else {
+				Toast.makeText(this, "Press the back button again to close HosTaGe", Toast.LENGTH_SHORT).show();
+				this.mCloseWarning = true;
+			}
+			//}
+		} else {
+			super.onBackPressed();
+			this.mDisplayedFragment = getFragmentManager().findFragmentById(R.id.content_frame);
+			configureFragment();
+
+			if (!(this.mDisplayedFragment instanceof UpNavigatibleFragment) || !((UpNavigatibleFragment) this.mDisplayedFragment).isUpNavigatible()) {
+				mDrawerToggle.setDrawerIndicatorEnabled(true);
+			} else {
+				mDrawerToggle.setDrawerIndicatorEnabled(false);
+			}
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public boolean onKeyDown(int keycode, KeyEvent e) {
+		switch (keycode) {
+		case KeyEvent.KEYCODE_MENU:
+			if (this.mDrawerToggle.isDrawerIndicatorEnabled()) {
+				if (this.mDrawerLayout.isDrawerOpen(Gravity.LEFT)) {
+					this.mDrawerLayout.closeDrawer(Gravity.LEFT);
+					return true;
+				}
+				this.mDrawerLayout.openDrawer(Gravity.LEFT);
+			}
+			return true;
+		}
+
+		return super.onKeyDown(keycode, e);
+	}
+
+	/**
+	 * Create a new intent intented for binding the hostage service to the activity
+	 *
+	 * @return the new service intent
+	 */
+	public Intent getServiceIntent() {
+		return new Intent(this, Hostage.class);
+	}
+
+	/**
+	 * Retrieves the currently displayed fragment
+	 *
+	 * @return the current fragment
+	 */
+	public Fragment getDisplayedFragment() {
+		return this.mDisplayedFragment;
+	}
+
+	/**
+	 * Retrieves the Hostage service instance
+	 * @return hostage service
+	 */
+	public Hostage getHostageService() {
+		return this.mHoneyService;
+	}
+
+	/**
+	 * Checks if the hostage service is bound to the activity
+	 * @return true,  if bound
+	 *         false, otherwise
+	 */
+	public boolean isServiceBound() {
+		return this.mServiceBound;
+	}
+
+	/**
+	 * Checks whether the hostage service is running
+	 * @return true,  if running
+	 *         false, otherwise
+	 */
+	public boolean isServiceRunning() {
+		ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
+		for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
+			if (service.service.getClassName().equals(Hostage.class.getName())) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * Start the monitoring of the given protocols in the hostage service
+	 *
+	 * @param protocols the protocols to start
+	 */
+	public void startMonitorServices(List<String> protocols){
+		for(String protocol: protocols){
+			// if the given protocol is ghost start a listener for every defined port for ghost
+			if(protocol.equals("GHOST")){
+				if(mProfileManager.getCurrentActivatedProfile() != null){
+					Profile profile = mProfileManager.getCurrentActivatedProfile();
+					if(profile.mGhostActive){
+						for(int port: profile.getGhostPorts()){
+							if(!getHostageService().isRunning(protocol, port)) getHostageService().startListener(protocol, port);
+						}
+					}
+				}
+			} else {
+				if(!getHostageService().isRunning(protocol)) getHostageService().startListener(protocol);
+			}
+		}
+	}
+
+	/**
+	 * Holds the index of the navigation items in an enum and also a reference to an Fragment class for each item
+	 */
+	public enum MainMenuItem {
+		HOME(0, HomeFragment.class),
+		THREAT_MAP(1, ThreatMapFragment.class),
+		RECORDS(2, RecordOverviewFragment.class),
+		STATISTICS(3, StatisticsFragment.class),
+		SERVICES(4, ServicesFragment.class),
+		PROFILE_MANAGER(5, ProfileManagerFragment.class),
+		SETTINGS(6, SettingsFragment.class),
+		HELP(7, Class.class),
+		APPLICATION_INFO(8, AboutFragment.class);
+
+		private int value;
+		private Class<?> klass;
+
+		private MainMenuItem(int value, Class<?> klass) {
+			this.value = value;
+			this.klass = klass;
+		}
+
+		static public MainMenuItem create(int value) {
+			if (value < 0 || value >= MainMenuItem.values().length)
+				return MainMenuItem.HOME;
+			return MainMenuItem.values()[value];
+		}
+
+		public static boolean hasClass(Class<?> klass){
+			for(MainMenuItem m: MainMenuItem.values()){
+				if(m.getKlass().equals(klass)) return true;
+			}
+
+			return false;
+		}
+
+		public int getValue() {
+			return value;
+		}
+
+		public Class<?> getKlass() {
+			return this.klass;
+		}
+	}
+
+	/**
+	 * The listener for the navigation drawer items.
+	 */
+	private class DrawerItemClickListener implements ListView.OnItemClickListener {
+		public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+			displayView(position);
+		}
+	}
+}

+ 40 - 0
src/de/tudarmstadt/informatik/hostage/ui/activity/ProfileEditActivity.java

@@ -0,0 +1,40 @@
+package de.tudarmstadt.informatik.hostage.ui2.activity;
+
+import android.content.Intent;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.drawable.BitmapDrawable;
+import android.net.Uri;
+import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.PreferenceActivity;
+import android.provider.MediaStore;
+
+import de.tudarmstadt.informatik.hostage.ui2.fragment.ProfileEditFragment;
+
+/**
+ * This activity manages an fragment for editing and creating a profile
+ *
+ * @author Alexander Brakowski
+ * @created 08.02.14 23:36
+ */
+public class ProfileEditActivity extends PreferenceActivity {
+	ProfileEditFragment editFragment;
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void onCreate(Bundle savedInstanceState){
+		super.onCreate(savedInstanceState);
+
+		// initializes the profile edit fragment
+		editFragment = new ProfileEditFragment();
+
+		// injects the fragment into the view
+		getFragmentManager().beginTransaction()
+				.replace(android.R.id.content, editFragment)
+				.commit();
+	}
+}

+ 64 - 0
src/de/tudarmstadt/informatik/hostage/ui/adapter/DrawerListAdapter.java

@@ -0,0 +1,64 @@
+package de.tudarmstadt.informatik.hostage.ui2.adapter;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import java.util.List;
+
+import de.tudarmstadt.informatik.hostage.R;
+import de.tudarmstadt.informatik.hostage.ui2.model.DrawerListItem;
+
+/**
+ * Creates the item view for the navigation drawer listview
+ *
+ * @author Alexander Brakowski
+ * @created 13.01.14 16:35
+ */
+public class DrawerListAdapter extends ArrayAdapter<DrawerListItem> {
+
+	/**
+	 * The context the adapter needs to retrieve resources
+	 */
+    private final Context mContext;
+
+	/**
+	 * The list items
+	 */
+    private final List<DrawerListItem> mValues;
+
+	/**
+	 * Create the list adapter
+	 *
+	 * @param context the context needed for resource retieval
+	 * @param objects all the items that should be displayed in the list
+	 */
+    public DrawerListAdapter(Context context, List<DrawerListItem> objects) {
+        super(context, R.layout.drawer_list_item, objects);
+        this.mContext = context;
+        this.mValues  = objects;
+    }
+
+	/**
+	 * {@inheritDoc}
+	 */
+    @Override
+    public View getView(int position, View convertView, ViewGroup parent) {
+        LayoutInflater inflater = (LayoutInflater) mContext
+                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+        View rowView = inflater.inflate(R.layout.drawer_list_item, parent, false);
+        TextView textView = (TextView) rowView.findViewById(R.id.drawer_listitem_text);
+        ImageView imageView = (ImageView) rowView.findViewById(R.id.drawer_listitem_icon);
+
+        DrawerListItem item = mValues.get(position);
+        textView.setText(item.text);
+        imageView.setImageResource(item.icon);
+
+        return rowView;
+    }
+}

+ 152 - 0
src/de/tudarmstadt/informatik/hostage/ui/adapter/ExpandableListAdapter.java

@@ -0,0 +1,152 @@
+package de.tudarmstadt.informatik.hostage.ui2.adapter;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseExpandableListAdapter;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import de.tudarmstadt.informatik.hostage.ui2.model.ExpandableListItem;
+
+/**
+ * Created by Julien on 06.02.14.
+ */
+public abstract class ExpandableListAdapter extends BaseExpandableListAdapter {
+
+    private Context _context;
+
+    // header titles
+    public List<String> _sectionHeader;
+    // data in format of header title, childs list
+    public HashMap<String, ArrayList<ExpandableListItem>> _sectionTitleToChildData;
+
+    /**
+     * Constructor
+     * @param context the context
+     * @param listSectionHeaders the section title
+     * @param dataMapping {@link ExpandableListItem ExpandableListItem} the data to visualise
+     */
+    public ExpandableListAdapter(Context context, List<String> listSectionHeaders,
+                                 HashMap<String, ArrayList<ExpandableListItem>> dataMapping) {
+        this._context = context;
+        this._sectionHeader = listSectionHeaders;
+        this._sectionTitleToChildData = dataMapping;
+    }
+
+    public void setData(HashMap<String, ArrayList<ExpandableListItem>> dataMapping){
+        this._sectionTitleToChildData = dataMapping;
+    }
+    public HashMap<String, ArrayList<ExpandableListItem>> getData(){
+        return this._sectionTitleToChildData;
+    }
+    public void setSectionHeader(List<String> listSectionHeaders){
+        this._sectionHeader = listSectionHeaders;
+    }
+    public List<String> getSectionHeaders(){
+        return this._sectionHeader;
+    }
+
+    @Override
+    public Object getChild(int section, int row) {
+        return this._sectionTitleToChildData.get(this._sectionHeader.get(section))
+                .get(row);
+    }
+
+    @Override
+    public long getChildId(int section, int row) {
+        return row;
+    }
+
+    @Override
+    public View getChildView(int section, final int row,
+                             boolean isLastChild, View convertView, ViewGroup parent) {
+        if (convertView == null) {
+            LayoutInflater infalInflater = (LayoutInflater) this._context
+                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+            convertView = infalInflater.inflate(this.getCellLayoutID(), null);
+        }
+        this.configureCellView(convertView, section, row);
+        return convertView;
+    }
+
+    @Override
+    public int getChildrenCount(int section) {
+        return this._sectionTitleToChildData.get(this._sectionHeader.get(section))
+                .size();
+    }
+
+    @Override
+    public Object getGroup(int section) {
+        return this._sectionHeader.get(section);
+    }
+
+    @Override
+    public int getGroupCount() {
+        return this._sectionHeader.size();
+    }
+
+    @Override
+    public long getGroupId(int section) {
+        return section;
+    }
+
+    @Override
+    public View getGroupView(int section, boolean isExpanded,
+                             View convertView, ViewGroup parent) {
+
+        if (convertView == null) {
+            LayoutInflater infalInflater = (LayoutInflater) this._context
+                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+            convertView = infalInflater.inflate(this.getSectionLayoutID(), null);
+        }
+        this.configureSectionHeaderView(convertView, section);
+
+        return convertView;
+    }
+
+    /**
+     * Return the {@link ExpandableListItem ExpandableListItem} for the given index path
+     * @param section int
+     * @param row int
+     * @return {@link ExpandableListItem ExpandableListItem}
+     */
+    public ExpandableListItem getDataForRow(int section, int row){
+        return this._sectionTitleToChildData.get(this._sectionHeader.get(section)).get(row);
+    }
+
+
+    /**
+     * Configure the items root view in here
+     * @param cell View, the root view
+     * @param section int
+     * @param row int
+     */
+    public abstract void configureCellView(View cell, int section, int row);
+    public abstract void configureSectionHeaderView(View sectionHeader, int section);
+
+    /**
+     * Returns the section header layout id.
+    * @return R.layout.list_section
+    * */
+    public abstract  int getSectionLayoutID();
+    /**
+     * Return the  root view layout id.
+     * @return R.layout.list_cell
+     * */
+    public abstract  int getCellLayoutID();
+
+
+    @Override
+    public boolean hasStableIds() {
+        return false;
+    }
+
+    @Override
+    public boolean isChildSelectable(int section, int row) {
+        return true;
+    }
+}

+ 235 - 0
src/de/tudarmstadt/informatik/hostage/ui/adapter/ProfileManagerListAdapter.java

@@ -0,0 +1,235 @@
+package de.tudarmstadt.informatik.hostage.ui2.adapter;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.graphics.BitmapFactory;
+import android.view.ContextThemeWrapper;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import de.tudarmstadt.informatik.hostage.Hostage;
+import de.tudarmstadt.informatik.hostage.R;
+import de.tudarmstadt.informatik.hostage.persistence.ProfileManager;
+import de.tudarmstadt.informatik.hostage.model.Profile;
+import de.tudarmstadt.informatik.hostage.ui2.activity.MainActivity;
+import de.tudarmstadt.informatik.hostage.ui2.activity.ProfileEditActivity;
+import de.tudarmstadt.informatik.hostage.ui2.layouts.FlowLayout;
+import de.tudarmstadt.informatik.hostage.ui2.swipelist.SwipeListView;
+
+/**
+ * This adapter creates the item views for the profile manager by making use the viewholder pattern
+ *
+ * @author Alexander Brakowski
+ * @created 14.01.14 18:00
+ */
+public class ProfileManagerListAdapter extends ArrayAdapter<Profile> {
+
+	/**
+	 * Holds our views, to reduce the number of view lookups immensly
+	 */
+	private class ViewHolder {
+		public TextView mLabelView;
+		public TextView mTextView;
+		public ImageView mImageSelected;
+		public ImageView mItemIcon;
+		public ImageButton mButtonEdit;
+		public ImageButton mButtonDelete;
+		public View mSeperator;
+		public FlowLayout mBadgesContainer;
+	}
+
+	/**
+	 * The context nedded for resource lookups
+	 */
+    private final Context mContext;
+
+	/**
+	 * The profiles to display in the list
+	 */
+    private final List<Profile> mValues;
+
+	/**
+	 * A reference to the list view itself
+	 */
+	private SwipeListView mList;
+
+	/**
+	 * A simple constructor to propagate this object with neccessary references to needed objects
+	 *
+	 * @param context needed for resource lookups
+	 * @param objects the profiles to display
+	 * @param list a reference to the list view
+	 */
+    public ProfileManagerListAdapter(Context context, List<Profile> objects, SwipeListView list) {
+        super(context, R.layout.profile_manager_list_item, objects);
+        this.mContext = context;
+        this.mValues = objects;
+	    this.mList = list;
+    }
+
+
+	/**
+	 * {@inheritDoc}
+	 */
+    @Override
+    public View getView(final int position, View convertView, ViewGroup parent) {
+	    LayoutInflater inflater = (LayoutInflater) mContext
+			    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+        View rowView = convertView;
+	    ViewHolder holder = null;
+
+	    final Profile item = mValues.get(position);
+
+	    // if the current item has the show tooltip flag set, render this item as an tooltip view
+	    if(item.mShowTooltip){
+		    rowView = inflater.inflate(R.layout.profile_manager_list_item_help, parent, false);
+		    rowView.findViewById(R.id.profile_manager_help_dismiss).setOnClickListener(new View.OnClickListener() {
+			    @Override
+			    public void onClick(View v) {
+				    ProfileManagerListAdapter.this.remove(item);
+				    ProfileManagerListAdapter.this.notifyDataSetChanged();
+				    mList.dismiss(position);
+
+				    // just show the tooltip as long as it was not dismissed
+				    MainActivity.getContext().getSharedPreferences(
+						    MainActivity.getContext().getString(R.string.shared_preference_path), Hostage.MODE_PRIVATE
+				    ).edit().putBoolean("dismissedProfileSwipeHelp", true).commit();
+			    }
+		    });
+	    } else {
+		    // put our views into an view holder, if it is new
+		    if (rowView == null || rowView.getTag() == null) {
+			    rowView = inflater.inflate(R.layout.profile_manager_list_item, parent, false);
+
+			    holder = new ViewHolder();
+			    holder.mLabelView = (TextView) rowView.findViewById(R.id.profile_manager_item_label);
+			    holder.mTextView = (TextView) rowView.findViewById(R.id.profile_manager_item_text);
+			    holder.mImageSelected = (ImageView) rowView.findViewById(R.id.profile_manager_item_activated);
+			    holder.mItemIcon = (ImageView) rowView.findViewById(R.id.profile_manager_item_image);
+			    holder.mButtonEdit = (ImageButton) rowView.findViewById(R.id.profile_manager_item_button_edit);
+			    holder.mButtonDelete = (ImageButton) rowView.findViewById(R.id.profile_manager_item_button_delete);
+			    holder.mSeperator = rowView.findViewById(R.id.profile_manager_item_seperator);
+			    holder.mBadgesContainer = (FlowLayout) rowView.findViewById(R.id.badges_container);
+
+			    rowView.setTag(holder);
+		    } else {
+			    // save the viewholder to the tag of the view, so we can reuse it later
+			    holder = (ViewHolder) rowView.getTag();
+		    }
+
+		    // swipe listview needs some cleanup
+		    ((SwipeListView) parent).recycle(rowView, position);
+
+		    // fill the item view with the correct data
+		    holder.mTextView.setText(item.mText);
+		    holder.mLabelView.setText(item.mLabel);
+
+		    if (item.getIconBitmap() != null) {
+			    //Bitmap bitmap = Bitmap.createScaledBitmap(item.getIconBitmap(), 32, 32, true);
+			    holder.mItemIcon.setImageBitmap(item.getIconBitmap());
+		    } else {
+			    holder.mItemIcon.setImageBitmap(BitmapFactory.decodeResource(MainActivity.context.getResources(), R.drawable.ic_launcher));
+		    }
+
+		    // open the profile edit activity, if the edit button was pressed
+		    holder.mButtonEdit.setOnClickListener(new View.OnClickListener() {
+			    @Override
+			    public void onClick(View v) {
+				    Intent intent = new Intent(mContext, ProfileEditActivity.class);
+				    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+				    intent.putExtra("profile_id", item.mId);
+
+				    mContext.startActivity(intent);
+			    }
+		    });
+
+		    // delete the profile, if the delete button was pressed. But shows an confirm dialog first.
+		    holder.mButtonDelete.setOnClickListener(new View.OnClickListener() {
+			    @Override
+			    public void onClick(View v) {
+				    new AlertDialog.Builder(mContext)
+						    .setTitle(R.string.delete_profile)
+						    .setMessage(R.string.really_want_delete_profiel)
+						    .setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
+							    @Override
+							    public void onClick(DialogInterface dialog, int which) {
+
+							    }
+						    })
+						    .setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
+							    public void onClick(DialogInterface dialog, int which) {
+								    ProfileManager profileManager = ProfileManager.getInstance();
+
+								    profileManager.deleteProfile(item);
+								    profileManager.getProfileListAdapter().notifyDataSetChanged();
+								    mList.closeOpenedItems();
+							    }
+						    })
+						    .setIcon(android.R.drawable.ic_dialog_alert)
+						    .show();
+			    }
+		    });
+
+		    // show all the active protocols of an profile in form of badges at the bottom of an profile list item
+		    holder.mBadgesContainer.removeAllViews();
+		    boolean hasProtocols = false;
+
+		    List<String> profiles = new LinkedList<String>(item.getActiveProtocols());
+
+		    if (item.mGhostActive) {
+			    profiles.add("GHOST");
+		    }
+
+		    for (String protocol : profiles) {
+			    hasProtocols = true;
+			    TextView textView = new TextView(new ContextThemeWrapper(mContext, R.style.ProfileManagerListBadge));
+			    textView.setText(protocol);
+			    holder.mBadgesContainer.addView(textView);
+		    }
+
+		    if (!hasProtocols) {
+			    holder.mBadgesContainer.setVisibility(View.INVISIBLE);
+		    } else {
+			    holder.mBadgesContainer.setVisibility(View.VISIBLE);
+		    }
+
+		    // do some styling when an profile is flagged as active
+		    RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) holder.mTextView.getLayoutParams();
+
+		    if (!item.mActivated) {
+			    lp.setMargins(0, 0, 0, 0);
+
+			    holder.mTextView.setLayoutParams(lp);
+
+			    holder.mImageSelected.setVisibility(View.GONE);
+		    } else {
+			    holder.mImageSelected.setVisibility(View.VISIBLE);
+		    }
+
+		    if (!item.isEditable()) {
+			    holder.mButtonDelete.setVisibility(View.GONE);
+			    holder.mSeperator.setVisibility(View.GONE);
+		    } else {
+			    holder.mButtonDelete.setVisibility(View.VISIBLE);
+			    holder.mSeperator.setVisibility(View.VISIBLE);
+		    }
+
+	    }
+
+        return rowView;
+    }
+
+
+}

+ 64 - 0
src/de/tudarmstadt/informatik/hostage/ui/adapter/RecordListAdapter.java

@@ -0,0 +1,64 @@
+package de.tudarmstadt.informatik.hostage.ui2.adapter;
+
+import android.content.Context;
+import android.view.View;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import de.tudarmstadt.informatik.hostage.R;
+import de.tudarmstadt.informatik.hostage.ui2.model.ExpandableListItem;
+
+public class RecordListAdapter extends ExpandableListAdapter {
+
+    /**
+     * Constructor
+     * @param context the context
+     * @param listSectionHeaders the section titles
+     * @param dataMapping HashMap<String, ArrayList<{@link ExpandableListItem ExpandableListItem}>> the data to visualise
+     */
+    public RecordListAdapter(Context context, List<String> listSectionHeaders, HashMap<String, ArrayList<ExpandableListItem>> dataMapping) {
+        super(context, listSectionHeaders, dataMapping);
+    }
+
+
+    /*****************************
+     *
+     *          Required Methods
+     *
+     * ***************************/
+
+    @Override
+    public void configureCellView(View cell, int section, int row) {
+        ExpandableListItem object = this.getDataForRow(section, row);
+        for (String key : object.getId_Mapping().keySet()){
+            int viewID = object.getId_Mapping().get(key);
+            String textualInfo = object.getData().get(key);
+            TextView tView = (TextView) cell.findViewById(viewID);
+            tView.setText(textualInfo);
+        }
+    }
+
+    @Override
+    public void configureSectionHeaderView(View sectionHeader, int section) {
+        int headerLabelID = R.id.sectionHeaderTitle;
+        int valueLabelID = R.id.sectionHeaderValue;
+        TextView tView = (TextView) sectionHeader.findViewById(headerLabelID);
+        TextView vView = (TextView) sectionHeader.findViewById(valueLabelID);
+        int value = this.getChildrenCount(section);
+        tView.setText(this._sectionHeader.get(section));
+        vView.setText("" + value);
+    }
+
+    @Override
+    public int getSectionLayoutID() {
+        return R.layout.expandable_section_header;
+    }
+
+    @Override
+    public int getCellLayoutID() {
+        return R.layout.record_list_item;
+    }
+}

+ 314 - 0
src/de/tudarmstadt/informatik/hostage/ui/adapter/ServicesListAdapter.java

@@ -0,0 +1,314 @@
+package de.tudarmstadt.informatik.hostage.ui2.adapter;
+
+import java.util.List;
+
+import android.annotation.SuppressLint;
+import android.annotation.TargetApi;
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.Build;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.CompoundButton;
+import android.widget.Switch;
+import android.widget.TextView;
+import de.tudarmstadt.informatik.hostage.R;
+import de.tudarmstadt.informatik.hostage.commons.HelperUtils;
+import de.tudarmstadt.informatik.hostage.model.Profile;
+import de.tudarmstadt.informatik.hostage.persistence.ProfileManager;
+import de.tudarmstadt.informatik.hostage.ui2.activity.MainActivity;
+import de.tudarmstadt.informatik.hostage.ui2.model.ServicesListItem;
+
+/**
+ * @author Daniel Lazar
+ * @created 06.02.14.
+ * a list adapter for loading switches and service information asynchronously
+ */
+public class ServicesListAdapter extends ArrayAdapter<ServicesListItem> {
+    private final Context context;
+    private final List<ServicesListItem> values;
+    int sdk = Build.VERSION.SDK_INT;
+    private Context mActivity;
+    private Switch mServicesSwitch;
+    private CompoundButton.OnCheckedChangeListener mListener;
+    private Profile mProfile;
+    private Integer[] mGhostPorts;
+
+    /**
+     * constructor
+     *
+     * @param context Context of the current activity
+     * @param objects List of ServicesListItem which contains all the protocols
+     */
+    public ServicesListAdapter(Context context, List<ServicesListItem> objects) {
+        super(context, R.layout.services_list_item, objects);
+
+        this.context = context;
+        this.values = objects;
+    }
+
+    /**
+     * method to save important information from parent fragment
+     *
+     * @param activity       activicty from parent fragment
+     * @param servicesSwitch the switch from parent fragment
+     * @param mainListener   Listener from parent fragment
+     */
+    public void setActivity(Context activity, Switch servicesSwitch, CompoundButton.OnCheckedChangeListener mainListener) {
+        mActivity = activity;
+        mServicesSwitch = servicesSwitch;
+        mListener = mainListener;
+    }
+
+    /**
+     * main method of ServicesListAdapter which initializes the holder if null
+     * Also activates protocols and switches
+     *
+     * @param position    current position in list
+     * @param convertView convert view
+     * @param parent the parent view group
+     * @return
+     */
+    @Override
+    public View getView(final int position, View convertView, ViewGroup parent) {
+        LayoutInflater inflater = (LayoutInflater) context
+                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        View rowView = convertView;
+
+        ViewHolder holder;
+
+        final ServicesListItem item = values.get(position);
+
+        if (rowView == null) {
+            rowView = inflater.inflate(R.layout.services_list_item, parent, false);
+
+            holder = new ViewHolder();
+            assert rowView != null;
+            holder.protocolName = (TextView) rowView.findViewById(R.id.services_item_name);
+            holder.recordedAttacks = (TextView) rowView.findViewById(R.id.services_item_rec_attacks);
+            holder.activated = (Switch) rowView.findViewById(R.id.services_item_switch);
+            holder.circle = rowView.findViewById(R.id.services_circle);
+            rowView.setTag(holder);
+        } else {
+            holder = (ViewHolder) rowView.getTag();
+        }
+
+        holder.protocolName.setText(item.protocol);
+        holder.activated.setTag(item);
+
+        this.updateStatus(item, holder);
+
+        holder.activated.setOnCheckedChangeListener(
+                new CompoundButton.OnCheckedChangeListener() {
+                    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+                        ServicesListItem item = (ServicesListItem) buttonView.getTag();
+                        mProfile = ProfileManager.getInstance().getCurrentActivatedProfile();
+                        //SK: Temp bugfix
+                        //if (!HelperUtils.isNetworkAvailable(mActivity)) {
+                        if (!HelperUtils.isWifiConnected(mActivity)) {
+                            if(!MainActivity.getInstance().getHostageService().hasRunningListeners()) {
+                                new AlertDialog.Builder(mActivity)
+                                        .setTitle(R.string.information)
+                                        .setMessage(R.string.wifi_not_connected_msg)
+                                        .setPositiveButton(android.R.string.ok,
+                                                new DialogInterface.OnClickListener() {
+                                                    public void onClick(DialogInterface dialog,
+                                                                        int which) {
+                                                    }
+                                                }
+                                        )
+                                        .setIcon(android.R.drawable.ic_dialog_info).show();
+                                if (buttonView.isChecked()) {
+                                    buttonView.setChecked(false);
+                                }
+                            }
+                        } else {
+                            //check if switch is set to ON and start the concrete listener for the protocol
+                            if (isChecked) {
+                                if(item.protocol.equals("GHOST")){
+                                    if(mProfile.mGhostActive){
+                                        mGhostPorts = mProfile.getGhostPorts();
+
+                                        if(mGhostPorts.length != 0) {
+                                            for(Integer port: mGhostPorts){
+                                                if(!MainActivity.getInstance().getHostageService().isRunning(item.protocol, port)) {
+                                                    MainActivity.getInstance().getHostageService().startListener(item.protocol, port);
+                                                }
+                                            }
+                                            //set the main switch to null, so that he won't react and starts all protocols
+                                            mServicesSwitch.setOnCheckedChangeListener(null);
+                                            mServicesSwitch.setChecked(true);
+                                            mServicesSwitch.setOnCheckedChangeListener(mListener);
+
+                                            if(!buttonView.isChecked()) {
+                                                buttonView.setChecked(true);
+                                            }
+                                        }
+                                    }
+                                    else {
+                                        if(buttonView.isChecked()) {
+                                            buttonView.setChecked(false);
+                                        }
+                                    }
+                                }
+                                else if (!MainActivity.getInstance().getHostageService().isRunning(item.protocol)) {
+                                    MainActivity.getInstance().getHostageService().startListener(item.protocol);
+
+                                    //set the main switch to null, so that he won't react and starts all protocols
+                                    mServicesSwitch.setOnCheckedChangeListener(null);
+                                    mServicesSwitch.setChecked(true);
+                                    mServicesSwitch.setOnCheckedChangeListener(mListener);
+                                    if(!buttonView.isChecked()) {
+                                        buttonView.setChecked(true);
+                                    }
+                                } else {
+                                    if(!buttonView.isChecked()) {
+                                        buttonView.setChecked(true);
+                                    }
+                                }
+                            } else {
+                                   if(item.protocol.equals("GHOST")) {
+                                       mGhostPorts = mProfile.getGhostPorts();
+                                       for(Integer port: mGhostPorts){
+                                           if(port != null) {
+                                               if(MainActivity.getInstance().getHostageService().isRunning("GHOST",port)){
+                                                   MainActivity.getInstance().getHostageService().stopListener("GHOST", port);
+                                               }
+                                           }
+                                       }
+                                       if(buttonView.isChecked()) {
+                                           buttonView.setChecked(false);
+                                       }
+                                   }
+                                   else if (MainActivity.getInstance().getHostageService().isRunning(item.protocol)) {
+                                        MainActivity.getInstance().getHostageService().stopListener(item.protocol);
+                                    }
+                                    if(buttonView.isChecked()) {
+                                        buttonView.setChecked(false);
+                                    }
+                            }
+                        }
+                    }
+                }
+        );
+        return rowView;
+    }
+
+    /**
+     * method to update the current status, which includes changing the attack indication circle and the number of attacks
+     *
+     * @param item   ServiceListItem which has information about current item, e.g. protocol, activated, attacks
+     * @param holder ViewHolder which represents the item in the View
+     */
+    private void updateStatus(ServicesListItem item, ViewHolder holder) {
+        if(item.protocol.equals("GHOST")){
+            mProfile = ProfileManager.getInstance().getCurrentActivatedProfile();
+            mGhostPorts = mProfile.getGhostPorts();
+
+            boolean ghostActive = false;
+            if(mGhostPorts.length != 0) {
+                for (Integer port : mGhostPorts) {
+                    if(port != null){
+                        if (MainActivity.getInstance().getHostageService().isRunning("GHOST", port)) {
+                            ghostActive = true;
+                        }
+                    }
+                }
+            }
+            if(ghostActive){
+                if(!holder.activated.isChecked()) {
+                    holder.activated.setChecked(true);
+                }
+
+                if (!MainActivity.getInstance().getHostageService().hasProtocolActiveAttacks(item.protocol)) {
+                    if (item.attacks > 0) {
+                        setBackground(holder, R.drawable.services_circle_yellow);
+                    } else {
+                        setBackground(holder, R.drawable.services_circle_green);
+                    }
+
+                } else {
+                    if (MainActivity.getInstance().getHostageService().hasProtocolActiveAttacks(item.protocol)) {
+                        setBackground(holder, R.drawable.services_circle_red);
+                    }
+                }
+
+            } else if (item.attacks > 0) {
+                if(holder.activated.isChecked()) {
+                    holder.activated.setChecked(false);
+                }
+                setBackground(holder, R.drawable.services_circle_yellow);
+            } else {
+                if(holder.activated.isChecked()) {
+                    holder.activated.setChecked(false);
+                }
+                setBackground(holder, R.drawable.services_circle);
+            }
+
+
+
+
+        }
+        else if (MainActivity.getInstance().getHostageService().isRunning(item.protocol)) {
+            if(!holder.activated.isChecked()) {
+                holder.activated.setChecked(true);
+            }
+            if (!MainActivity.getInstance().getHostageService().hasProtocolActiveAttacks(item.protocol)) {
+                if (item.attacks > 0) {
+                    setBackground(holder, R.drawable.services_circle_yellow);
+                } else {
+                    setBackground(holder, R.drawable.services_circle_green);
+                }
+
+            } else {
+                if (MainActivity.getInstance().getHostageService().hasProtocolActiveAttacks(item.protocol)) {
+                    setBackground(holder, R.drawable.services_circle_red);
+                }
+            }
+        } else if (item.attacks > 0) {
+            if(holder.activated.isChecked()) {
+                holder.activated.setChecked(false);
+            }
+            setBackground(holder, R.drawable.services_circle_yellow);
+        } else {
+            if(holder.activated.isChecked()) {
+                holder.activated.setChecked(false);
+            }
+            setBackground(holder, R.drawable.services_circle);
+        }
+        holder.recordedAttacks
+                .setText(String.format(MainActivity.getContext().getResources().getString(R.string.recorded_attacks) + "  %d", Integer.valueOf(item.attacks)));
+    }
+
+    /**
+     * changes the indicator circle of a service
+     *
+     * @param holder   ViewHolder which represents the item in the View
+     * @param drawable int which represents the ID of the drawable we want to display, e.g. on a present attack it should be R.drawable.services_circle_red
+     */
+	@SuppressLint("NewApi")
+	private void setBackground(ViewHolder holder, int drawable) {
+        if (sdk < Build.VERSION_CODES.JELLY_BEAN) {
+            holder.circle.setBackgroundDrawable(MainActivity.getInstance().getResources().getDrawable(drawable));
+        } else {
+            holder.circle.setBackground(MainActivity.getInstance().getResources().getDrawable(drawable));
+        }
+    }
+
+    /**
+     * ViewHolder stands for a row in the view
+     */
+    private class ViewHolder {
+
+        public TextView protocolName;
+
+        public TextView recordedAttacks;
+
+        public Switch activated;
+
+        public View circle;
+    }
+}

+ 121 - 0
src/de/tudarmstadt/informatik/hostage/ui/adapter/StatisticListAdapter.java

@@ -0,0 +1,121 @@
+package de.tudarmstadt.informatik.hostage.ui2.adapter;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import de.tudarmstadt.informatik.hostage.R;
+import de.tudarmstadt.informatik.hostage.ui2.model.PlotComparisonItem;
+
+/**
+ * Created by Julien on 22.02.14.
+ */
+public class StatisticListAdapter extends ArrayAdapter<PlotComparisonItem> {
+
+    /**
+     * Holds all necessary subviews in the rootview.
+     */
+    private class ViewHolder {
+        public TextView titleView;
+        public TextView valueView;
+        public TextView colorView;
+    }
+
+    /**
+     * A ValueFormatter converts information containing in the
+     * {@link de.tudarmstadt.informatik.hostage.ui2.model.PlotComparisonItem PlotComparisonItems}
+     * in a readable format.
+     */
+    public interface ValueFormatter {
+        public String convertValueForItemToString(PlotComparisonItem item);
+    }
+
+    private ValueFormatter formatter;
+    private final Context context;
+    private List<PlotComparisonItem> values;
+
+    /**
+     * Set the value formatter.
+     * @param formatter ValueFormatter
+     */
+    public void setValueFormatter(ValueFormatter formatter){
+        this.formatter = formatter;
+    }
+
+    /**
+     * Contructor
+     * @param context the context
+     * @param objects the repesenting {@link de.tudarmstadt.informatik.hostage.ui2.model.PlotComparisonItem PlotComparisonItems}
+     */
+    public StatisticListAdapter(Context context, List<PlotComparisonItem> objects) {
+        super(context, getLayoutID(), objects);
+        List<PlotComparisonItem> list = objects == null ? new ArrayList<PlotComparisonItem>() : objects;
+        this.context = context;
+        this.values = list;
+    }
+
+    /**
+     * Set the representing {@link de.tudarmstadt.informatik.hostage.ui2.model.PlotComparisonItem PlotComparisonItems}.
+     * @param list List<PlotComparisonItem>
+     */
+    public void setValues(List<PlotComparisonItem> list){
+        this.values = list;
+    }
+
+    @Override
+    public View getView(final int position, View convertView, ViewGroup parent) {
+        LayoutInflater inflater = (LayoutInflater) context
+                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+        View rowView = convertView;
+        ViewHolder holder = null;
+
+        final PlotComparisonItem item = values.get(position);
+
+        if(rowView == null){
+            rowView = inflater.inflate(getLayoutID() , parent, false);
+            holder = new ViewHolder();
+            holder.titleView = (TextView) rowView.findViewById(R.id.title_text_view);
+            holder.valueView = (TextView) rowView.findViewById(R.id.value_text_view);
+            holder.colorView = (TextView) rowView.findViewById(R.id.color_view);
+            rowView.setTag(holder);
+        } else {
+            holder = (ViewHolder) rowView.getTag();
+        }
+
+
+        this.configureView(holder, item);
+
+        return rowView;
+    }
+
+    /**
+     * Returns the items layout ID.
+     * @return int layoutID
+     */
+    static public int getLayoutID(){
+        return R.layout.plot_list_item;
+    }
+
+    /**
+     * Configure the items rootview in here.
+     * @param holder ViewHolder
+     * @param item {@link de.tudarmstadt.informatik.hostage.ui2.model.PlotComparisonItem PlotComparisonItem}
+     */
+    private void configureView(ViewHolder holder, PlotComparisonItem item){
+        holder.colorView.setBackgroundColor(item.getColor());
+        holder.titleView.setText(item.getTitle());
+
+        if (this.formatter == null){
+            holder.valueView.setText("" + item.getValue2());
+        } else {
+            holder.valueView.setText(this.formatter.convertValueForItemToString(item));
+        }
+    }
+}

+ 199 - 0
src/de/tudarmstadt/informatik/hostage/ui/dialog/ChecklistDialog.java

@@ -0,0 +1,199 @@
+package de.tudarmstadt.informatik.hostage.ui2.dialog;
+
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.content.DialogInterface;
+import android.os.Bundle;
+
+import java.util.ArrayList;
+
+import de.tudarmstadt.informatik.hostage.R;
+import de.tudarmstadt.informatik.hostage.ui2.activity.MainActivity;
+
+//import android.content.Intent;
+/**
+ * Created by Julien on 16.02.14.
+ */
+@SuppressLint("ValidFragment")
+public class ChecklistDialog extends DialogFragment {
+	
+	private ArrayList<Integer> mSelectedItems;
+	private ArrayList<String> itemTitles;
+    private ChecklistDialogListener mListener;
+    
+    private int selectedIndex;
+    private boolean isMultipleChoice;
+    
+    public String title;
+	
+	/**
+     * The ChecklistDialogListener will be called if the user clicked a "cancel" or "ok" button.
+     * */
+    @SuppressLint("ValidFragment")
+	public interface ChecklistDialogListener {
+        /**
+         * Called if the user tapped "ok"
+         * @param dialog {@link ChecklistDialog ChecklistDialog}
+         */
+        public void onDialogPositiveClick(ChecklistDialog dialog);
+
+        /**
+         * Called if the user tapped "cancel".
+         * @param dialog {@link ChecklistDialog ChecklistDialog}
+         */
+        public void onDialogNegativeClick(ChecklistDialog dialog);
+    }
+
+    /**
+     * Returns the dialog title
+     * @return title String
+     */
+    public String getTitle(){
+    	return this.title;
+    }
+
+    /**
+     * Returns true if the checklist dialog is a multiple choice dialog.
+     * @return boolean isMultipleChoice
+     * */
+    public boolean isMultipleChoice(){
+    	return this.isMultipleChoice;
+    }
+
+    /*CONSTRUCTOR*/
+    /**
+     * The Constructor Method
+     * @param  title String
+     * @param itemTitles ArrayList<String> item titles list
+     * @param selected boolean[] an array of bools descriping the position of all the selected titles.
+     * @param isMultipleChoice boolean isMultipleChoice
+     * @param listener ChecklistDialogListener an user "event" listener
+     *
+     * */
+    public ChecklistDialog(String title, ArrayList<String> itemTitles, boolean[] selected, boolean isMultipleChoice , ChecklistDialogListener listener){
+    	mListener = listener;
+    	this.mSelectedItems = new ArrayList<Integer>();
+	    
+    	this.isMultipleChoice = isMultipleChoice;
+	    this.title = title;
+	    this.itemTitles = itemTitles;
+
+	    
+	    
+	    boolean[] selectedArray = new boolean[this.itemTitles.size()];
+
+	    if(this.isMultipleChoice){
+		    for(int i = 0; i < this.itemTitles.size(); i++){
+		    	boolean isSelected = selected[i];
+		    	selectedArray[i] = isSelected;
+		    	if(isSelected) this.mSelectedItems.add(i);
+		    }
+	    } else {
+		    for(int i = 0; i < this.itemTitles.size(); i++){
+		    	boolean isSelected = selected[i];
+		    	selectedArray[i] = isSelected;
+		    	if(isSelected) this.selectedIndex = i;
+		    }
+	    }
+    }
+    
+    @Override
+    public void onAttach(Activity activity) {
+        super.onAttach(activity);
+        
+        if(this.mListener == null)
+        try {
+            
+            if (activity.getClass().equals(MainActivity.class)){
+            	mListener = (ChecklistDialogListener) (((MainActivity)activity).getDisplayedFragment());
+            } else {
+            	mListener = (ChecklistDialogListener) activity;
+            }
+        } catch (ClassCastException e) {
+            throw new ClassCastException(activity.toString()
+                    + " must implement ChecklistDialogListener");
+        }
+    }
+
+    /**
+     * Return the selected titles.
+     * @return ArrayList<String>
+     */
+    public ArrayList<String> getSelectedItemTitles(){
+    	ArrayList<String> list = new ArrayList<String>();
+        if (this.mSelectedItems == null){
+            return  list;
+        }
+    	for(Integer i : this.mSelectedItems){
+    		list.add(this.itemTitles.get(i.intValue()));
+    	}
+        if (this.mSelectedItems.size() == 0 && !this.isMultipleChoice){
+            list.add(this.itemTitles.get(this.selectedIndex));
+       }
+    	return list;
+    }
+
+
+	
+	@Override
+	public Dialog onCreateDialog(Bundle savedInstanceState) {
+	    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+	    
+	    CharSequence[] titles = this.itemTitles.toArray(new CharSequence[this.itemTitles.size()]);
+	    
+	    boolean[] selectedArray = new boolean[this.itemTitles.size()];
+	    for(Integer selection : this.mSelectedItems){
+	    	selectedArray[selection.intValue()] = true;
+	    }
+
+	    if(this.isMultipleChoice){
+	        builder.setTitle(title).setMultiChoiceItems(titles, selectedArray,
+                    new DialogInterface.OnMultiChoiceClickListener() {
+             public void onClick(DialogInterface dialog, int which,
+                     boolean isChecked) {
+          		   if (isChecked) {
+                     	mSelectedItems.add(which);
+                 	} else if (mSelectedItems.contains(which)) {
+                     	mSelectedItems.remove(Integer.valueOf(which));
+                 	}
+             }
+         }).setPositiveButton(R.string.button_title_apply, new DialogInterface.OnClickListener() {
+             public void onClick(DialogInterface dialog, int id) {
+                 mListener.onDialogPositiveClick(ChecklistDialog.this);
+             }
+         })
+         .setNegativeButton(R.string.button_title_cancel, new DialogInterface.OnClickListener() {
+             public void onClick(DialogInterface dialog, int id) {
+                 mListener.onDialogNegativeClick(ChecklistDialog.this);
+             }
+         });
+	        
+	    } else {
+	    	
+	    	 builder.setTitle(title).setSingleChoiceItems(titles, this.selectedIndex, 
+	    			 new DialogInterface.OnClickListener() {
+	             public void onClick(DialogInterface dialog, int id) {
+	                 mSelectedItems.clear();
+	            	 mSelectedItems.add(id);
+	             }
+	         })
+	         .setPositiveButton(R.string.button_title_apply, new DialogInterface.OnClickListener() {
+             public void onClick(DialogInterface dialog, int id) {
+                 mListener.onDialogPositiveClick(ChecklistDialog.this);
+             }
+	         })
+	         .setNegativeButton(R.string.button_title_cancel, new DialogInterface.OnClickListener() {
+	             public void onClick(DialogInterface dialog, int id) {
+	                 mListener.onDialogNegativeClick(ChecklistDialog.this);
+	             }
+	         });
+	    }
+	    
+	    return builder.create();
+	}
+}
+
+

+ 303 - 0
src/de/tudarmstadt/informatik/hostage/ui/dialog/DateTimeDialogFragment.java

@@ -0,0 +1,303 @@
+package de.tudarmstadt.informatik.hostage.ui2.dialog;
+
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.AlertDialog.Builder;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.content.DialogInterface;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.DatePicker;
+import android.widget.DatePicker.OnDateChangedListener;
+import android.widget.TimePicker;
+import android.widget.TimePicker.OnTimeChangedListener;
+
+import java.util.Calendar;
+
+import de.tudarmstadt.informatik.hostage.R;
+import de.tudarmstadt.informatik.hostage.ui2.activity.MainActivity;
+/**
+ * Created by Julien on 16.02.14.
+ */
+@SuppressLint("ValidFragment")
+public class DateTimeDialogFragment extends DialogFragment implements OnDateChangedListener, OnTimeChangedListener {
+    // Define constants for date-time picker.
+    public final static int DATE_PICKER = 1;
+    public final static int TIME_PICKER = 2;
+    public final static int DATE_TIME_PICKER = 3;
+
+    // DatePicker reference
+    public DatePicker datePicker;
+
+    // TimePicker reference
+    public TimePicker timePicker;
+
+    // Calendar reference
+    private Calendar mCalendar;
+
+    // Define activity
+    private Activity activity;
+
+    // Define Dialog type
+    private int DialogType;
+
+    // Define Dialog view
+    private View mView;
+
+    // Constructor start
+    public DateTimeDialogFragment(Activity activity) {
+        this(activity, DATE_TIME_PICKER);
+    }
+
+    /**
+     * Constructor
+     * @param activity the activity
+     * @param DialogType, what kind of dialog it is (TIME_PICKER, DATE_PICKER, DATE_TIME_PICKER)
+     */
+    public DateTimeDialogFragment(Activity activity, int DialogType) {
+
+        this.activity = activity;
+        this.DialogType = DialogType;
+
+        LayoutInflater inflater = activity.getLayoutInflater();
+        mView = inflater.inflate(R.layout.date_time_dialog, null);
+
+        this.setupRootView(mView);
+
+    }
+
+
+    @Override
+    public void onConfigurationChanged(Configuration newConfig){
+        super.onConfigurationChanged(newConfig);
+        LayoutInflater inflater = LayoutInflater.from(this.activity);
+
+        ViewGroup container = (ViewGroup) this.mView.getParent();
+
+        container.removeView(this.mView);
+
+        mView = inflater.inflate(R.layout.date_time_dialog, null);
+        container.addView(mView);
+        this.setupRootView(mView);
+    }
+
+    /**
+     * Configure the root view in here.
+     * @param mView, root view
+     */
+    private void setupRootView(View mView){
+
+        mCalendar = Calendar.getInstance();
+
+        datePicker = (DatePicker) mView.findViewById(R.id.DatePicker);
+        datePicker.init(mCalendar.get(Calendar.YEAR), mCalendar.get(Calendar.MONTH), mCalendar.get(Calendar.DAY_OF_MONTH), this);
+
+
+        timePicker = (TimePicker) mView.findViewById(R.id.TimePicker);
+
+        setIs24HourView(true);
+        setCalendarViewShown(false);
+
+        switch (DialogType) {
+            case DATE_PICKER:
+                timePicker.setVisibility(View.GONE);
+                break;
+            case TIME_PICKER:
+                datePicker.setVisibility(View.GONE);
+                break;
+        }
+    }
+
+    /**
+     * Set the current date.
+     * @param timeInMillis, date in milliseconds
+     */
+    public void setDate(long timeInMillis){
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTimeInMillis (timeInMillis);
+
+        int year    = calendar.get(Calendar.YEAR) ;
+        int month   = calendar.get(Calendar.MONTH);
+        int day     = calendar.get(Calendar.DATE);
+        int hour    = calendar.get(Calendar.HOUR);
+        int min     = calendar.get(Calendar.MINUTE);
+
+        datePicker.updateDate(year, month, day);
+        timePicker.setCurrentHour(hour);
+        timePicker.setCurrentMinute(min);
+    }
+
+    /**
+     * Returns the current selected date.
+     * @return long, date in milliseconds
+     */
+   public long getDate(){
+	   
+       int day = datePicker.getDayOfMonth();
+       int month = datePicker.getMonth();
+       int year =  datePicker.getYear();
+       
+       int hourOfDay = timePicker.getCurrentHour();
+       int minute = timePicker.getCurrentMinute();
+
+       Calendar calendar = Calendar.getInstance();
+
+       calendar.set(year, month, day, hourOfDay, minute);
+
+       return calendar.getTime().getTime();
+   }
+
+    /**
+     * The listener which will be called if the user tapped "cancel" or "ok"
+     */
+    public interface DateTimeDialogFragmentListener {
+        /**
+         * Called if the user tapped "ok"
+         * @param dialog {@link DateTimeDialogFragment DateTimeDialogFragment}
+         */
+        public void onDateTimePickerPositiveClick(DateTimeDialogFragment dialog);
+
+        /**
+         * Called if the user tapped "cancel"
+         * @param dialog {@link DateTimeDialogFragment DateTimeDialogFragment}
+         */
+        public void onDateTimePickerNegativeClick(DateTimeDialogFragment dialog);
+    }
+    private DateTimeDialogFragmentListener mListener;
+
+    /**
+     * Set the user interaction listener.
+     * @param listener DateTimeDialogFragmentListener
+     */
+    public void setDateChangeListener(DateTimeDialogFragmentListener listener){
+        this.mListener = listener;
+    }
+
+    @Override
+    public void onAttach(Activity activity) {
+        super.onAttach(activity);
+        try {
+            if (this.mListener == null){
+                if (activity.getClass().equals(MainActivity.class)){
+                    mListener = (DateTimeDialogFragmentListener) (((MainActivity)activity).getDisplayedFragment());
+                } else {
+                    mListener = (DateTimeDialogFragmentListener) activity;
+                }
+            }
+        } catch (ClassCastException e) {
+            throw new ClassCastException(activity.toString()
+                    + " must implement DateTimeDialogListener");
+        }
+    }
+
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+
+        Builder builder = new AlertDialog.Builder(activity);
+
+        builder.setView(mView);
+
+        builder.setMessage(activity.getString(R.string.rec_set_date))
+                .setPositiveButton(activity.getString(R.string.rec_set),
+						new DialogInterface.OnClickListener() {
+							public void onClick(DialogInterface dialog, int id) {
+								mListener
+										.onDateTimePickerPositiveClick(DateTimeDialogFragment.this);
+							}
+						})
+                .setNegativeButton(activity.getString(R.string.rec_cancel),
+						new DialogInterface.OnClickListener() {
+							public void onClick(DialogInterface dialog, int id) {
+								mListener
+										.onDateTimePickerNegativeClick(DateTimeDialogFragment.this);
+								DateTimeDialogFragment.this.getDialog().cancel();
+							}
+						}); 
+
+        return builder.create();
+    }
+
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+        timePicker.setOnTimeChangedListener(this);
+    }
+
+    /**
+     * Returns the value of the given field after computing the field values by calling complete() first.
+     * @param field int
+     * @return int
+     */
+    public int get(final int field) {
+        return mCalendar.get(field);
+    }
+
+    /**
+     * Set the time picker style.
+     * @param is24HourView
+     */
+    public void setIs24HourView(boolean is24HourView) {
+        timePicker.setIs24HourView(is24HourView);
+    }
+
+    /**
+     * Show / hide the calendar view of the DatePicker.
+     * @param calendarView boolean
+     */
+    public void setCalendarViewShown(boolean calendarView) {
+        datePicker.setCalendarViewShown(calendarView);
+    }
+
+
+
+    /**
+     * Handles date change event.
+     * @param view DatePicker
+     * @param year changed year
+     * @param monthOfYear changed month of Year
+     * @param dayOfMonth changed day of Month
+     */
+    public void onDateChanged(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
+        mCalendar.set(year, monthOfYear, dayOfMonth, mCalendar.get(Calendar.HOUR_OF_DAY), mCalendar.get(Calendar.MINUTE));
+    }
+
+    /**
+     * Handles on time changed events.
+     * @param view TimePicker
+     * @param hourOfDay changed hour
+     * @param minute changed minute
+     */
+    public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
+        mCalendar.set(mCalendar.get(Calendar.YEAR), mCalendar.get(Calendar.MONTH), mCalendar.get(Calendar.DAY_OF_MONTH), hourOfDay, minute);
+    }
+
+    // MAYBE NEED IN FUTURE DEVELOPMENT
+    // UNUSED
+//    public long getDateTimeMillis() {
+//        return mCalendar.getTimeInMillis();
+//    }
+//    public boolean CalendarViewShown() {
+//        return datePicker.getCalendarViewShown();
+//    }
+//    public boolean is24HourView() {
+//        return timePicker.is24HourView();
+//    }
+//    public void updateDate(int year, int monthOfYear, int dayOfMonth) {
+//        datePicker.updateDate(year, monthOfYear, dayOfMonth);
+//    }
+//
+//    public void updateTime(int currentHour, int currentMinute) {
+//        timePicker.setCurrentHour(currentHour);
+//        timePicker.setCurrentMinute(currentMinute);
+//    }
+//
+//    public String getDateTime() {
+//        DateFormat dateFormat = android.text.format.DateFormat.getDateFormat(activity);
+//        return dateFormat.format(mCalendar.getTime());
+//    }
+}

+ 52 - 0
src/de/tudarmstadt/informatik/hostage/ui/fragment/AboutFragment.java

@@ -0,0 +1,52 @@
+package de.tudarmstadt.informatik.hostage.ui2.fragment;
+
+import android.app.Activity;
+import android.app.Fragment;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.text.method.LinkMovementMethod;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import de.tudarmstadt.informatik.hostage.Hostage;
+import de.tudarmstadt.informatik.hostage.R;
+
+/**
+ * Shows informations about the developers of the app
+ *
+ * Created by Fabio Arnold on 25.02.14.
+ * displays credits for the app
+ */
+public class AboutFragment extends Fragment {
+	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
+		super.onCreateView(inflater, container, savedInstanceState);
+
+		final Activity activity = getActivity();
+		if (activity != null) {
+			activity.setTitle(getResources().getString(R.string.drawer_app_info));
+		}
+
+		View rootView = inflater.inflate(R.layout.fragment_about, container, false);
+        PackageManager manager = Hostage.getContext().getPackageManager();
+        PackageInfo info = null;
+        try {
+            info = manager.getPackageInfo(Hostage.getContext().getPackageName(), 0);
+        } catch (PackageManager.NameNotFoundException e) {
+            e.printStackTrace();
+        }
+        String versionApp;
+        versionApp = info.versionName;
+
+        TextView hostage = (TextView) rootView.findViewById(R.id.hostage);
+        TextView version = (TextView) rootView.findViewById(R.id.hostageVersion);
+
+        version.setText("ver. "+versionApp);
+		hostage.setMovementMethod(LinkMovementMethod.getInstance());
+        version.setMovementMethod(LinkMovementMethod.getInstance());
+
+		return rootView;
+	}
+}

+ 85 - 0
src/de/tudarmstadt/informatik/hostage/ui/fragment/ConnectionInfoDialogFragment.java

@@ -0,0 +1,85 @@
+package de.tudarmstadt.informatik.hostage.ui2.fragment;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.view.ContextThemeWrapper;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+
+import de.tudarmstadt.informatik.hostage.R;
+import de.tudarmstadt.informatik.hostage.ui2.model.LogFilter;
+import de.tudarmstadt.informatik.hostage.ui2.activity.MainActivity;
+
+/**
+ * Created by Fabio Arnold on 03.03.14.
+ * displays details about the current connection
+ */
+public class ConnectionInfoDialogFragment extends DialogFragment {
+	public Dialog onCreateDialog(Bundle savedInstance) {
+		// the data we want to display
+		String ssid = "undefined";
+		String bssid = "undefined";
+		String internalIP = "undefined";
+		String externalIP = "undefined";
+
+		// get infos about the current connection using SharedPreferences
+		final Activity activity = getActivity();
+		if (activity != null) {
+			SharedPreferences sharedPreferences = activity.getSharedPreferences(getString(R.string.connection_info), Context.MODE_PRIVATE);
+			ssid = sharedPreferences.getString(getString(R.string.connection_info_ssid), "");
+			bssid = sharedPreferences.getString(getString(R.string.connection_info_bssid), "");
+			internalIP = sharedPreferences.getString(getString(R.string.connection_info_internal_ip), "");
+			externalIP = sharedPreferences.getString(getString(R.string.connection_info_external_ip), "");
+		}
+
+		// inflate the layout with a dark theme
+		Context context = new ContextThemeWrapper(getActivity(), android.R.style.Theme_Holo);
+		LayoutInflater localInflater = getActivity().getLayoutInflater().cloneInContext(context);
+		View view = localInflater.inflate(R.layout.fragment_connectioninfo_dialog, null);
+
+		// assign values in layout
+		if (view != null) {
+			((TextView)view.findViewById(R.id.connectioninfo_ssid_value)).setText(ssid);
+			((TextView)view.findViewById(R.id.connectioninfo_bssid_value)).setText(bssid);
+			((TextView)view.findViewById(R.id.connectioninfo_internalip_value)).setText(internalIP);
+			((TextView)view.findViewById(R.id.connectioninfo_externalip_value)).setText(externalIP);
+		}
+
+		// capture the SSID for the button action
+		final String filterSSID = ssid;
+
+		// build the actual dialog
+		AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(), AlertDialog.THEME_HOLO_DARK);
+		builder.setView(view);
+		builder.setTitle(R.string.title_connection_info);
+		builder.setIcon(android.R.drawable.ic_dialog_info);
+		builder.setPositiveButton(R.string.show_records, new DialogInterface.OnClickListener() {
+			@Override
+			public void onClick(DialogInterface dialog, int which) {
+				ArrayList<String> ssids = new ArrayList<String>();
+				ssids.add(filterSSID);
+
+				LogFilter filter = new LogFilter();
+				filter.setESSIDs(ssids);
+
+				RecordOverviewFragment recordOverviewFragment = new RecordOverviewFragment();
+				recordOverviewFragment.setFilter(filter);
+				recordOverviewFragment.setGroupKey("ESSID");
+
+				MainActivity.getInstance().injectFragment(recordOverviewFragment);
+			}
+		});
+		builder.setNegativeButton(R.string.close, null);
+
+		return builder.create();
+	}
+}

+ 543 - 0
src/de/tudarmstadt/informatik/hostage/ui/fragment/HomeFragment.java

@@ -0,0 +1,543 @@
+package de.tudarmstadt.informatik.hostage.ui2.fragment;
+
+import com.google.android.gms.analytics.HitBuilders;
+import com.google.android.gms.analytics.Tracker;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Fragment;
+import android.app.FragmentManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.SharedPreferences;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.v4.content.LocalBroadcastManager;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.CompoundButton;
+import android.widget.ImageView;
+import android.widget.Switch;
+import android.widget.TextView;
+
+import de.tudarmstadt.informatik.hostage.Hostage;
+import de.tudarmstadt.informatik.hostage.HostageApplication;
+import de.tudarmstadt.informatik.hostage.R;
+import de.tudarmstadt.informatik.hostage.commons.HelperUtils;
+import de.tudarmstadt.informatik.hostage.persistence.ProfileManager;
+import de.tudarmstadt.informatik.hostage.model.Profile;
+import de.tudarmstadt.informatik.hostage.persistence.HostageDBOpenHelper;
+import de.tudarmstadt.informatik.hostage.ui2.model.LogFilter;
+import de.tudarmstadt.informatik.hostage.ui2.activity.MainActivity;
+import de.tudarmstadt.informatik.hostage.ui2.fragment.opengl.ThreatIndicatorGLRenderer;
+import de.tudarmstadt.informatik.hostage.system.Device;
+
+/**
+ * This fragments displays the current hostage state and attacks on the device in form of an animation and simple view components
+ *
+ * @author Alexander Brakowski
+ * @created 13.01.14 19:06
+ */
+
+public class HomeFragment extends TrackerFragment {
+
+	/**
+	 * View objects from the layout
+	 */
+	private Switch mHomeSwitchConnection;
+	private TextView mHomeTextName;
+	private TextView mHomeTextSecurity;
+	private TextView mHomeTextAttacks;
+	private TextView mHomeTextProfile;
+	private TextView mHomeTextProfileHeader;
+	private ImageView mHomeProfileImage;
+	private ImageView mHomeConnectionInfoButton;
+	private View mRootView;
+
+	/**
+	 * This handles all the broadcasts from the Hostage service
+	 */
+	private BroadcastReceiver mReceiver;
+
+	/**
+	 * A change listener for the monitor switch
+	 */
+	private CompoundButton.OnCheckedChangeListener mSwitchChangeListener = null;
+
+
+	private int mDefaultTextColor;
+
+	/**
+	 * A reference to the profile manager
+	 */
+	private ProfileManager mProfileManager;
+
+	/**
+	 * A shared preference that holds all the connection info of the current network connection
+	 */
+	private SharedPreferences mConnectionInfo;
+
+    /**
+     * Hold the shared preferences for the app
+     */
+    private SharedPreferences mSharedPreferences;
+
+	/**
+	 * An Helper to access the sqllite database with all the records
+	 */
+	private HostageDBOpenHelper mDbHelper;
+
+	/**
+	 * Holds a state if the broadcast receiver is registered to the hostage service
+ 	 */
+	private boolean mReceiverRegistered;
+
+	/**
+	 * Holds a state if the hostage service is active
+	 */
+	private boolean isActive = false;
+
+	/**
+	 * Holds a state if the device is currently connected to a network
+	 */
+	private boolean isConnected = false;
+
+	public HomeFragment() {
+	}
+
+	/**
+	 * Looks up all the neccessary views in the layout
+	 */
+	private void assignViews() {
+		mHomeSwitchConnection = (Switch) mRootView.findViewById(R.id.home_switch_connection);
+		mHomeTextName = (TextView) mRootView.findViewById(R.id.home_text_name);
+		mHomeTextSecurity = (TextView) mRootView.findViewById(R.id.home_text_security);
+		mHomeTextAttacks = (TextView) mRootView.findViewById(R.id.home_text_attacks);
+		mHomeTextProfile = (TextView) mRootView.findViewById(R.id.home_text_profile);
+		mHomeTextProfileHeader = (TextView) mRootView.findViewById(R.id.home_text_profile_header);
+		mHomeProfileImage = (ImageView) mRootView.findViewById(R.id.home_image_profile);
+		mHomeConnectionInfoButton = (ImageView) mRootView.findViewById(R.id.home_button_connection_info);
+	}
+
+	/**
+	 * Registers the broadcast receiver with the hostage service
+	 */
+	private void registerBroadcastReceiver() {
+		if (!mReceiverRegistered) {
+			LocalBroadcastManager.getInstance(getActivity()).registerReceiver(mReceiver, new IntentFilter(getString(R.string.broadcast)));
+			this.mReceiverRegistered = true;
+		}
+	}
+
+	/**
+	 * Unregisters the broadcast receiver
+	 */
+	private void unregisterBroadcastReceiver() {
+		if (mReceiverRegistered) {
+			LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(mReceiver);
+			this.mReceiverRegistered = false;
+		}
+	}
+
+	/**
+	 * Sets the view state to not active.
+	 * This means hiding and graying out all the informations in the view, that are not important, if the service is not active.
+	 *
+	 * @param initial indicates that the method was called on creation of view
+	 */
+	public void setStateNotActive(boolean initial) {
+		mHomeTextName.setTextColor(getResources().getColor(R.color.light_grey));
+		mHomeTextSecurity.setTextColor(getResources().getColor(R.color.light_grey));
+		mHomeTextAttacks.setTextColor(getResources().getColor(R.color.light_grey));
+		mHomeTextProfile.setTextColor(getResources().getColor(R.color.light_grey));
+		mHomeTextProfileHeader.setTextColor(getResources().getColor(R.color.light_grey));
+
+		if (!initial) {
+			ThreatIndicatorGLRenderer.setThreatLevel(ThreatIndicatorGLRenderer.ThreatLevel.NOT_MONITORING);
+		}
+
+		mHomeSwitchConnection.setChecked(false);
+		isActive = false;
+	}
+
+	/**
+	 * Alias for calling setStateNotActive with the initial value being false
+	 */
+	public void setStateNotActive() {
+		setStateNotActive(false);
+	}
+
+	/**
+	 * Alias for calling setStateActive with the initial value being false
+	 */
+	public void setStateActive() {
+		setStateActive(false);
+	}
+
+	/**
+	 * Sets the state of the view to active.
+	 * That means that all the information showing the active state of the hostage service is being displayed.
+	 *
+	 * @param initial indicates that the method was called on creation of view
+	 */
+	public void setStateActive(boolean initial) {
+		mHomeTextAttacks.setVisibility(View.VISIBLE);
+		mHomeTextSecurity.setVisibility(View.VISIBLE);
+
+		mHomeTextName.setTextColor(mDefaultTextColor);
+		mHomeTextProfile.setTextColor(mDefaultTextColor);
+		mHomeTextProfileHeader.setTextColor(mDefaultTextColor);
+
+		if (!initial) {
+			ThreatIndicatorGLRenderer.setThreatLevel(ThreatIndicatorGLRenderer.ThreatLevel.NO_THREAT);
+		}
+
+		mHomeSwitchConnection.setChecked(true);
+		isActive = true;
+	}
+
+	/**
+	 * Sets the state of the view to not connected by hiding information about the attacks.
+	 */
+	public void setStateNotConnected() {
+		mHomeTextSecurity.setVisibility(View.INVISIBLE);
+		mHomeTextAttacks.setVisibility(View.INVISIBLE);
+		mHomeTextProfile.setVisibility(View.INVISIBLE);
+		mHomeTextProfileHeader.setVisibility(View.INVISIBLE);
+		mHomeProfileImage.setVisibility(View.INVISIBLE);
+		mHomeConnectionInfoButton.setVisibility(View.INVISIBLE);
+
+		mHomeTextName.setText(R.string.not_connected);
+		isConnected = false;
+	}
+
+	/**
+	 * Sets the state of the view to connected by showing informations about attacks
+	 */
+	public void setStateConnected() {
+		mHomeTextProfile.setVisibility(View.VISIBLE);
+		mHomeTextProfileHeader.setVisibility(View.VISIBLE);
+		mHomeProfileImage.setVisibility(View.VISIBLE);
+		mHomeConnectionInfoButton.setVisibility(View.VISIBLE);
+		isConnected = true;
+	}
+
+	/**
+	 * Updates the view.
+	 *
+	 * That means: updating the number of attacks on the view,
+	 *             updating the threat level,
+	 *             updating the connection state,
+	 *             updating the monitoring state
+	 */
+	public void updateUI() {
+		Profile profile = mProfileManager.getCurrentActivatedProfile();
+		if (profile != null) {
+			mHomeTextProfile.setText(profile.mLabel);
+			mHomeProfileImage.setImageBitmap(profile.getIconBitmap());
+		}
+
+		// if the device is connected to an network display the network name
+        //SK: Temporary Bugfix
+		//if (HelperUtils.isNetworkAvailable(getActivity())) {
+        if (HelperUtils.isWifiConnected(getActivity())) {
+			setStateConnected();
+			String ssid = mConnectionInfo.getString(getString(R.string.connection_info_ssid), "\"\"");
+			mHomeTextName.setText(ssid.substring(1,ssid.length() - 1));
+		} else {
+			setStateNotConnected();
+		}
+
+		boolean hasActiveListeners = false;
+		int totalAttacks = mDbHelper.numBssidSeen(mConnectionInfo.getString(getString(R.string.connection_info_bssid), null));
+		ThreatIndicatorGLRenderer.ThreatLevel threatLevel = ThreatIndicatorGLRenderer.ThreatLevel.NOT_MONITORING;
+
+		// decides which threat level to display
+		if (MainActivity.getInstance().getHostageService() != null) {
+			if (MainActivity.getInstance().getHostageService().hasRunningListeners()) {
+				hasActiveListeners = true;
+
+				if (MainActivity.getInstance().getHostageService().hasActiveAttacks() && totalAttacks > 0) {
+					threatLevel = ThreatIndicatorGLRenderer.ThreatLevel.LIVE_THREAT;
+				} else if (totalAttacks > 0) {
+					threatLevel = ThreatIndicatorGLRenderer.ThreatLevel.PAST_THREAT;
+				} else {
+					threatLevel = ThreatIndicatorGLRenderer.ThreatLevel.NO_THREAT;
+				}
+			}
+		}
+
+		// if the monitoring is running show the information
+		if (hasActiveListeners) {
+			setStateActive(true);
+
+			if(!isConnected){
+				ThreatIndicatorGLRenderer.setThreatLevel(ThreatIndicatorGLRenderer.ThreatLevel.NO_THREAT);
+				mHomeTextAttacks.setText("");
+				mHomeTextSecurity.setText("");
+			} else {
+				switch (threatLevel) {
+					case NO_THREAT:
+						mHomeTextAttacks.setText(R.string.zero_attacks);
+						mHomeTextSecurity.setText(R.string.secure);
+						mHomeTextAttacks.setTextColor(getResources().getColor(R.color.holo_dark_green));
+						mHomeTextSecurity.setTextColor(getResources().getColor(R.color.holo_dark_green));
+						break;
+					case PAST_THREAT:
+						mHomeTextAttacks.setText(totalAttacks
+								+ (totalAttacks == 1 ? getResources().getString(R.string.attack) : getResources().getString(R.string.attacks))
+								+ getResources().getString(R.string.recorded));
+						mHomeTextSecurity.setText(R.string.insecure);
+						mHomeTextAttacks.setTextColor(getResources().getColor(R.color.holo_yellow));
+						mHomeTextSecurity.setTextColor(getResources().getColor(R.color.holo_yellow));
+						break;
+					case LIVE_THREAT:
+						mHomeTextAttacks.setText(totalAttacks
+								+ (totalAttacks == 1 ? getResources().getString(R.string.attack) : getResources().getString(R.string.attacks))
+								+ getResources().getString(R.string.recorded));
+						mHomeTextSecurity.setText(R.string.insecure);
+						mHomeTextAttacks.setTextColor(getResources().getColor(R.color.holo_red));
+						mHomeTextSecurity.setTextColor(getResources().getColor(R.color.holo_red));
+						break;
+				}
+
+				ThreatIndicatorGLRenderer.setThreatLevel(threatLevel);
+			}
+		} else {
+			setStateNotActive();
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+		super.onCreateView(inflater, container, savedInstanceState);
+
+		final Activity activity = getActivity();
+		if (activity != null) {
+			activity.setTitle(getResources().getString(R.string.drawer_overview));
+		}
+
+		mDbHelper = new HostageDBOpenHelper(getActivity());
+
+		mProfileManager = ProfileManager.getInstance();
+		mConnectionInfo = getActivity().getSharedPreferences(getString(R.string.connection_info), Context.MODE_PRIVATE);
+
+		mRootView = inflater.inflate(R.layout.fragment_home, container, false);
+		assignViews();
+
+		// hook up the connection info button
+		mHomeConnectionInfoButton.setOnClickListener(new View.OnClickListener() {
+			@Override
+			public void onClick(View v) {
+				final FragmentManager fragmentManager = getFragmentManager();
+				if (fragmentManager != null) {
+					ConnectionInfoDialogFragment connectionInfoDialogFragment = new ConnectionInfoDialogFragment();
+					connectionInfoDialogFragment.show(fragmentManager.beginTransaction(), connectionInfoDialogFragment.getTag());
+				}
+			}
+		});
+
+		mDefaultTextColor = mHomeTextName.getCurrentTextColor();
+
+		// sets state and connection initially to off
+		setStateNotActive(true);
+		setStateNotConnected();
+
+		// register the broadcast receiver
+		mReceiver = new BroadcastReceiver() {
+			@SuppressLint("NewApi")
+			@Override
+			public void onReceive(Context context, Intent intent) {
+				if (getUserVisibleHint())
+					updateUI();
+			}
+		};
+		registerBroadcastReceiver();
+
+		updateUI();
+
+		// connects the switch listener to the switch button
+		mHomeSwitchConnection = (Switch) mRootView.findViewById(R.id.home_switch_connection);
+		mHomeSwitchConnection.setSaveEnabled(false);
+
+		if (mSwitchChangeListener == null) {
+			mSwitchChangeListener = new CompoundButton.OnCheckedChangeListener() {
+				public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+					// displays a alert dialog if no network is available
+
+                    //SK: Temporary bugfix to limit to wifi
+					//if (!HelperUtils.isNetworkAvailable(getActivity())) {
+                    if (!HelperUtils.isWifiConnected(getActivity())) {
+
+						//new AlertDialog.Builder(getActivity()).setTitle(R.string.information).setMessage(R.string.network_not_connected_msg)
+                        new AlertDialog.Builder(getActivity()).setTitle(R.string.information).setMessage(R.string.wifi_not_connected_msg)
+								.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+									public void onClick(DialogInterface dialog, int which) {
+
+									}
+								}).setIcon(android.R.drawable.ic_dialog_info).show();
+
+						setStateNotActive();
+						setStateNotConnected();
+					} else {
+						if (isChecked) {
+
+							boolean protocolActivated = false;
+
+                            mSharedPreferences = getActivity().getSharedPreferences(getString(R.string.shared_preference_path), Hostage.MODE_PRIVATE);
+
+
+                            if(mSharedPreferences.getBoolean( "isFirstEmulation", true)) {
+                                //Notify Porthack is not installed to user
+                                if(!Device.isPorthackInstalled()) {
+                                    new AlertDialog.Builder(getActivity())
+                                            .setTitle(R.string.information)
+                                            .setMessage(R.string.no_portbinder_msg2)
+                                            .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+                                                public void onClick(DialogInterface dialog, int which) {
+
+                                                }
+                                            })
+                                            .setNegativeButton(R.string.help, new DialogInterface.OnClickListener() {
+                                                public void onClick(DialogInterface dialog, int which) {
+                                                    MainActivity.getInstance().displayView(MainActivity.MainMenuItem.SETTINGS.getValue());
+
+
+                                                }
+                                            })
+
+                                            .setIcon(android.R.drawable.ic_dialog_info).show();
+
+                                }
+
+                                // Disable hint for 'first' time emulation notification
+                                SharedPreferences.Editor editor = mSharedPreferences.edit();
+                                editor.putBoolean("isFirstEmulation", false);
+                                editor.commit();
+
+                            }
+
+							if (ProfileManager.getInstance().getCurrentActivatedProfile() == null) {
+								// starts all services
+								MainActivity.getInstance().startMonitorServices(Arrays.asList(getResources().getStringArray(R.array.protocols)));
+							} else {
+								// starts the services that are actived in the current profile
+								ProfileManager profileManager = ProfileManager.getInstance();
+
+								if (profileManager.isRandomActive()) {
+									profileManager.randomizeProtocols(profileManager.getRandomProfile());
+								}
+
+								Profile currentProfile = profileManager.getCurrentActivatedProfile();
+								List<String> protocols = currentProfile.getActiveProtocols();
+
+								if(protocols.size() > 0 || currentProfile.mGhostActive){
+									protocols.add("GHOST");
+									MainActivity.getInstance().startMonitorServices(protocols);
+									protocolActivated = true;
+								}
+							}
+
+							if (protocolActivated) {
+								setStateActive();
+							} else {
+								// no protocol was started, so show alert dialog
+								new AlertDialog.Builder(getActivity()).setTitle(R.string.information).setMessage(R.string.profile_no_services_msg)
+										.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+											public void onClick(DialogInterface dialog, int which) {
+
+											}
+										}).setIcon(android.R.drawable.ic_dialog_info).show();
+
+								setStateNotActive();
+							}
+						} else {
+							// stop hostage service and all listeners
+							if (MainActivity.getInstance().getHostageService() != null) {
+								MainActivity.getInstance().getHostageService().stopListeners();
+								MainActivity.getInstance().stopAndUnbind();
+							}
+							setStateNotActive();
+						}
+					}
+				}
+			};
+		}
+		mHomeSwitchConnection.setOnCheckedChangeListener(mSwitchChangeListener);
+
+		// connects the profile text an click listener
+		mRootView.findViewById(R.id.home_profile_details).setOnClickListener(new View.OnClickListener() {
+			@Override
+			public void onClick(View v) {
+				Fragment fragment = new ProfileManagerFragment();
+				MainActivity.getInstance().injectFragment(fragment);
+			}
+		});
+
+		// connect the attacks text to an click listener
+		View.OnClickListener attackClickListener = new View.OnClickListener() {
+			@Override
+			public void onClick(View v) {
+				String ssid = mConnectionInfo.getString(getString(R.string.connection_info_ssid), "");
+				if (!ssid.isEmpty()) {
+					ArrayList<String> ssids = new ArrayList<String>();
+					ssids.add(ssid);
+
+					LogFilter filter = new LogFilter();
+					filter.setESSIDs(ssids);
+
+					RecordOverviewFragment recordOverviewFragment = new RecordOverviewFragment();
+					recordOverviewFragment.setFilter(filter);
+					recordOverviewFragment.setGroupKey("ESSID");
+
+					MainActivity.getInstance().injectFragment(recordOverviewFragment);
+				}
+			}
+		};
+
+		mHomeTextAttacks.setOnClickListener(attackClickListener);
+		mHomeTextSecurity.setOnClickListener(attackClickListener);
+
+		return mRootView;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void onStop() {
+		super.onStop();
+		unregisterBroadcastReceiver();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void onStart() {
+		super.onStart();
+		registerBroadcastReceiver();
+		updateUI();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void onDestroy() {
+		super.onDestroy();
+		unregisterBroadcastReceiver();
+	}
+}

+ 118 - 0
src/de/tudarmstadt/informatik/hostage/ui/fragment/PreferenceHostageFrament.java

@@ -0,0 +1,118 @@
+package de.tudarmstadt.informatik.hostage.ui2.fragment;
+
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.preference.EditTextPreference;
+import android.preference.Preference;
+import android.preference.PreferenceFragment;
+
+import java.util.HashMap;
+
+import de.tudarmstadt.informatik.hostage.R;
+
+/**
+ * Manages and creates the application preferences view
+ *
+ * @author Alexander Brakowski
+ * @created 02.03.14 21:03
+ */
+public class PreferenceHostageFrament extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener {
+
+	/**
+	 * Maps an text preference to an suffix string
+	 */
+	private HashMap<String, String> mSuffixMap;
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void onCreate(Bundle savedInstanceState){
+		super.onCreate(savedInstanceState);
+
+		// these preferences are all text preferences
+		String[] textPreferences = new String[]{
+				"pref_external_location",
+				"pref_upload_server",
+				"pref_max_connections",
+				"pref_timeout",
+				"pref_sleeptime",
+				"pref_location_time",
+				"pref_location_retries"
+		};
+
+		// map the text preferences to suffixes
+		this.mSuffixMap = new HashMap<String, String>();
+		this.mSuffixMap.put("pref_timeout", "s");
+		this.mSuffixMap.put("pref_sleeptime", "ms");
+		this.mSuffixMap.put("pref_location_time", "ms");
+
+		addPreferencesFromResource(R.xml.settings_preferences);
+
+		for(String k: textPreferences){
+			updatePreferenceSummary(k);
+		}
+	}
+
+	/**
+	 * Updates the summary text of the given preference
+	 *
+	 * @param key the preference key
+	 */
+	private void updatePreferenceSummary(String key){
+		Preference p = findPreference(key);
+		SharedPreferences sharedPreferences = this.getPreferenceManager().getSharedPreferences();
+
+		if(p != null && p instanceof EditTextPreference){
+			String suffix = "";
+
+			if(this.mSuffixMap.containsKey(key)){
+				suffix = this.mSuffixMap.get(key);
+			}
+
+			p.setSummary(sharedPreferences.getString(key, "") + " " + suffix);
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void onResume() {
+		super.onResume();
+		getPreferenceManager().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void onPause() {
+		getPreferenceManager().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
+		super.onPause();
+	}
+
+/*	@Override
+	public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
+		super.onPreferenceTreeClick(preferenceScreen, preference);
+
+		if (preference instanceof PreferenceScreen) {
+			if(MainActivity.getInstance().mDisplayedFragment != null && MainActivity.getInstance().mDisplayedFragment instanceof UpNavigatible){
+				((UpNavigatible) MainActivity.getInstance().mDisplayedFragment).setUpNavigatible(true);
+				((UpNavigatible) MainActivity.getInstance().mDisplayedFragment).setUpFragment(SettingsFragment.class);
+				MainActivity.getInstance().setDrawerIndicatorEnabled(false);
+				return true;
+			}
+		}
+
+		return false;
+	}*/
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
+		updatePreferenceSummary(key);
+	}
+}

+ 320 - 0
src/de/tudarmstadt/informatik/hostage/ui/fragment/ProfileEditFragment.java

@@ -0,0 +1,320 @@
+package de.tudarmstadt.informatik.hostage.ui2.fragment;
+
+import android.app.ActionBar;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.drawable.BitmapDrawable;
+import android.net.Uri;
+import android.os.Bundle;
+import android.preference.CheckBoxPreference;
+import android.preference.EditTextPreference;
+import android.preference.Preference;
+import android.preference.PreferenceCategory;
+import android.preference.PreferenceFragment;
+import android.preference.PreferenceManager;
+import android.provider.MediaStore;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.LinearLayout;
+
+import java.util.HashMap;
+
+import de.tudarmstadt.informatik.hostage.R;
+import de.tudarmstadt.informatik.hostage.persistence.ProfileManager;
+import de.tudarmstadt.informatik.hostage.model.Profile;
+
+/**
+ * Creates an preference screen to edit an profile
+ *
+ * @author Alexander Brakowski
+ * @created 08.02.14 23:39
+ */
+public class ProfileEditFragment extends PreferenceFragment implements
+		SharedPreferences.OnSharedPreferenceChangeListener {
+
+	/**
+	 * Holds the shared preference editor for out preference screen
+	 */
+	private SharedPreferences.Editor mPrefs;
+
+	/**
+	 * A map which mirrors the state protocols in the preferencescreen
+	 */
+	private HashMap<String, Boolean> mProfileProtocols;
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void onCreate(Bundle savedInstanceState){
+		getActivity().getActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
+		super.onCreate(savedInstanceState);
+
+		LayoutInflater inflater = (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+		// remove default action bar and replace it with an "done"/"discard" action bar
+		View actionBarButtons = inflater.inflate(R.layout.actionbar_donebar, new LinearLayout(getActivity()), false);
+		getActivity().getActionBar().setCustomView(actionBarButtons);
+
+		View doneButton = actionBarButtons.findViewById(R.id.action_done);
+		View cancelButton = actionBarButtons.findViewById(R.id.action_cancel);
+
+		// add click listener for the save button
+		doneButton.setOnClickListener(new View.OnClickListener() {
+			@Override
+			public void onClick(View v) {
+				SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
+				ProfileManager pmanager = ProfileManager.getInstance();
+
+				Profile profile = getProfile();
+
+				boolean createNew = false;
+
+				// no profile was given to the fragment, which means this is a new profile
+				if(profile == null){
+					profile = new Profile();
+					createNew = true;
+				} else {
+					// profile was given, if profile is not editable, clone the profile and make it editable
+					if(!profile.isEditable()){
+						profile = profile.cloneProfile();
+						profile.mEditable = true;
+						createNew = true;
+					}
+				}
+
+				// update the profile object data with data from the preferences
+				profile.mLabel = prefs.getString("pref_profile_general_name", profile.mLabel);
+				profile.mIconPath = prefs.getString("pref_profile_general_image", profile.mIconPath);
+				profile.mText = prefs.getString("pref_profile_general_description", profile.mText);
+				profile.mGhostActive = prefs.getBoolean("pref_profile_protocols_ghost_active", profile.mGhostActive);
+				profile.mGhostPorts = prefs.getString("pref_profile_protocols_ghost_text", "");
+
+				if(profile.mLabel == null || profile.mLabel.isEmpty()){
+					new AlertDialog.Builder(getActivity()).setTitle(R.string.information).setMessage(R.string.profile_needs_name)
+							.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+								public void onClick(DialogInterface dialog, int which) {
+
+								}
+							}).setIcon(android.R.drawable.ic_dialog_info).show();
+					return;
+				}
+
+				if(profile.mGhostPorts.isEmpty()){
+					profile.mGhostActive = false;
+				}
+
+				profile.mActiveProtocols = new HashMap<String, Boolean>(mProfileProtocols);
+
+				// persist the changes of the profile
+				if(createNew){
+					profile.mId = -1;
+					profile.mIconId = 0;
+					profile.mIconName = "";
+					profile.mIsRandom = false;
+					profile.mIcon = null;
+					pmanager.addProfile(profile);
+				} else {
+					pmanager.persistProfile(profile);
+				}
+
+				getActivity().finish();
+			}
+		});
+
+		cancelButton.setOnClickListener(new View.OnClickListener() {
+			@Override
+			public void onClick(View v) {
+				getActivity().finish();
+			}
+		});
+
+		Profile profile = getProfile();
+		mPrefs = PreferenceManager.getDefaultSharedPreferences(getActivity()).edit();
+
+		String pname = "",
+			   pimage = null,
+			   pdesc = "",
+			   pghost = "";
+
+		boolean pbghost = false;
+
+		if(profile != null){
+			pname = profile.mLabel;
+			pimage = profile.mIconPath;
+			pdesc = profile.mText;
+			pghost = profile.mGhostPorts;
+			pbghost = profile.mGhostActive;
+		}
+
+		// fill the preferences of the preference screen with data from the profile object
+		mPrefs.putString("pref_profile_general_name", pname);
+		mPrefs.putString("pref_profile_general_image", pimage);
+		mPrefs.putString("pref_profile_general_description", pdesc);
+		mPrefs.putString("pref_profile_protocols_ghost_text", pghost);
+		mPrefs.putBoolean("pref_profile_protocols_ghost_active", pbghost);
+
+		mPrefs.commit();
+
+		// create the preference view
+		addPreferencesFromResource(R.xml.profile_preferences);
+
+		Preference pref = findPreference("pref_profile_general_image");
+
+		assert pref != null;
+
+		if(profile != null){
+			pref.setIcon(profile.getIconDrawable());
+			mProfileProtocols = new HashMap<String, Boolean>(profile.mActiveProtocols);
+		} else {
+			mProfileProtocols = new HashMap<String, Boolean>();
+		}
+
+		// show an image chooser dialog when pressing the image preference
+		pref.setOnPreferenceClickListener(
+				new Preference.OnPreferenceClickListener() {
+					@Override
+					public boolean onPreferenceClick(Preference preference) {
+						Intent intent = new Intent();
+						intent.setType("image/*");
+						intent.setAction(Intent.ACTION_GET_CONTENT);
+						int PICK_IMAGE = 1;
+						startActivityForResult(Intent.createChooser(intent, getString(R.string.select_icon)), PICK_IMAGE);
+						return true;
+					}
+				}
+		);
+
+		if(profile != null){
+			findPreference("pref_profile_general_name").setSummary(profile.mLabel);
+			findPreference("pref_profile_general_description").setSummary(profile.mText);
+
+			if(!profile.mGhostPorts.isEmpty()) findPreference("pref_profile_protocols_ghost_text").setSummary(profile.mGhostPorts);
+		}
+
+		if(profile == null || profile.isEditable()){
+			getPreferenceScreen().removePreference(findPreference("pref_profile_warning"));
+		}
+
+		PreferenceCategory protocolsCategory = (PreferenceCategory) findPreference("pref_profile_protocols_settings");
+		String[] protocols = getResources().getStringArray(R.array.protocols);
+		String[] protocols_summary = getResources().getStringArray(R.array.protocols_description);
+
+		// add all available protocols to the preference screen with an checkbox
+		for(int i = 0; i<protocols.length; i++){
+			if(protocols[i].equals("GHOST")) continue;
+
+			mPrefs.putBoolean("pref_profile_protocol_" + protocols[i], profile != null && profile.isProtocolActive(protocols[i]));
+			mPrefs.commit();
+
+			CheckBoxPreference check = new CheckBoxPreference(getActivity());
+			check.setTitle(protocols[i]);
+			check.setKey("pref_profile_protocol_" + protocols[i]);
+			check.setSummary(protocols_summary[i]);
+
+			protocolsCategory.addPreference(check);
+		}
+	}
+
+	/**
+	 * Retrieve the given profile from the intent
+	 * @return the profile
+	 */
+	public Profile getProfile(){
+		ProfileManager pmanager = ProfileManager.getInstance();
+
+		Intent intent = getActivity().getIntent();
+		int profile_id = intent.getIntExtra("profile_id", -1);
+
+		if(profile_id != -1){
+			return pmanager.getProfile(profile_id);
+		}
+
+		return null;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void onResume() {
+		super.onResume();
+		getPreferenceManager().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void onPause() {
+		getPreferenceManager().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
+		super.onPause();
+	}
+
+	/**
+	 * Called when a shared preference is changed, added, or removed. This
+	 * may be called even if a preference is set to its existing value.
+	 *
+	 * <p>This callback will be run on your main thread.
+	 *
+	 * @param sharedPreferences The {@link android.content.SharedPreferences} that received
+	 *                          the change.
+	 * @param key               The key of the preference that was changed, added, or
+	 */
+	@Override
+	public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
+		Preference p = findPreference(key);
+
+		if(p instanceof EditTextPreference){
+			p.setSummary(sharedPreferences.getString(key, ""));
+		} else if(p instanceof CheckBoxPreference && !p.getKey().equals("pref_profile_protocols_ghost_active")){
+			mProfileProtocols.put(p.getTitle().toString(), ((CheckBoxPreference) p).isChecked());
+			//System.out.println("------------------------------- P: " + ((CheckBoxPreference) p).isChecked());
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void onActivityResult(int requestCode, int resultCode, Intent imageReturnedIntent) {
+		super.onActivityResult(requestCode, resultCode, imageReturnedIntent);
+
+		if(resultCode == Activity.RESULT_OK){
+			Cursor cursor = getActivity().getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
+					new String[]{
+							MediaStore.Images.Media.DATA,
+							MediaStore.Images.Media.DATE_ADDED,
+							MediaStore.Images.ImageColumns.ORIENTATION
+					},
+			MediaStore.Images.Media.DATE_ADDED, null, "date_added ASC");
+
+			String filePath = "";
+			if(cursor != null && cursor.moveToFirst())
+			{
+				do {
+					filePath = Uri.parse(cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA))).toString();
+				} while(cursor.moveToNext());
+				cursor.close();
+			}
+
+			Preference pref = findPreference("pref_profile_general_image");
+
+			BitmapFactory.Options options = new BitmapFactory.Options();
+			options.inPreferredConfig = Bitmap.Config.ARGB_8888;
+			Bitmap bitmap = BitmapFactory.decodeFile(filePath, options);
+
+			pref.setIcon(new BitmapDrawable(getResources(), bitmap));
+
+			mPrefs.putString("pref_profile_general_image", filePath);
+			mPrefs.commit();
+		}
+	}
+}

+ 154 - 0
src/de/tudarmstadt/informatik/hostage/ui/fragment/ProfileManagerFragment.java

@@ -0,0 +1,154 @@
+package de.tudarmstadt.informatik.hostage.ui2.fragment;
+
+import android.app.Fragment;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.fortysevendeg.android.swipelistview.BaseSwipeListViewListener;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import de.tudarmstadt.informatik.hostage.Hostage;
+import de.tudarmstadt.informatik.hostage.R;
+import de.tudarmstadt.informatik.hostage.persistence.ProfileManager;
+import de.tudarmstadt.informatik.hostage.model.Profile;
+import de.tudarmstadt.informatik.hostage.ui2.activity.MainActivity;
+import de.tudarmstadt.informatik.hostage.ui2.activity.ProfileEditActivity;
+import de.tudarmstadt.informatik.hostage.ui2.adapter.ProfileManagerListAdapter;
+import de.tudarmstadt.informatik.hostage.ui2.swipelist.SwipeListView;
+
+/**
+ * Displays a list of all available profiles and allows invocation of the edit activity for an profile
+ *
+ * @author Alexander Brakowski
+ * @created 14.01.14 15:05
+ */
+public class ProfileManagerFragment extends TrackerFragment {
+
+	/**
+	 * The adapter for the profile list
+	 */
+	private ProfileManagerListAdapter mAdapter;
+
+	/**
+	 * Holds the shared preferences for the app
+	 */
+	private SharedPreferences mSharedPreferences;
+
+	public ProfileManagerFragment(){}
+
+	/**
+	 * Holds the listview for the profile list
+	 */
+	private SwipeListView list;
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                             Bundle savedInstanceState) {
+
+	    super.onCreateView(inflater, container, savedInstanceState);
+	    getActivity().setTitle(getResources().getString(R.string.drawer_profile_manager));
+
+		// show action bar menu items
+		setHasOptionsMenu(true);
+
+		// inflate the view
+        View rootView = inflater.inflate(R.layout.fragment_profile_manager, container, false);
+	    list = (SwipeListView) rootView.findViewById(R.id.profile_manager_listview);
+
+		final ProfileManager pmanager = ProfileManager.getInstance();
+		pmanager.loadData();
+
+	    String sharedPreferencePath = MainActivity.getContext().getString(R.string.shared_preference_path);
+	    mSharedPreferences = MainActivity.getContext().getSharedPreferences(sharedPreferencePath, Hostage.MODE_PRIVATE);
+
+        final List<Profile> strList = new LinkedList<Profile>(pmanager.getProfilesList());
+
+		// show an help item in the listview to indicate, that the items in the list are swipeable
+	    if(strList.size() > 0 && !mSharedPreferences.getBoolean("dismissedProfileSwipeHelp", false)){
+		    Profile tProfile = new Profile();
+		    tProfile.mShowTooltip = true;
+
+			strList.add(1, tProfile);
+	    }
+
+		mAdapter = new ProfileManagerListAdapter(getActivity(), strList, list);
+		pmanager.setProfileListAdapter(mAdapter);
+
+        list.setAdapter(mAdapter);
+
+		// add open and close actions to the items of the list view
+		list.setSwipeListViewListener(new BaseSwipeListViewListener() {
+			@Override
+			public void onOpened(int position, boolean toRight){
+				Profile profile = mAdapter.getItem(position);
+				if(profile.mShowTooltip){
+					mAdapter.remove(profile);
+					strList.remove(profile);
+					list.dismiss(position);
+
+					mSharedPreferences.edit().putBoolean("dismissedProfileSwipeHelp", true).commit();
+				}
+			}
+
+			@Override
+			public void onClickFrontView(int position) {
+				// active the pressed profile
+				Profile profile = mAdapter.getItem(position);
+				if(profile.mShowTooltip) return;
+
+				pmanager.activateProfile(profile);
+
+				mAdapter.notifyDataSetChanged();
+			}
+		});
+
+        return rootView;
+    }
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void onResume() {
+		super.onResume();
+		list.closeOpenedItems();
+		mAdapter.notifyDataSetChanged();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+		// Inflate the menu items for use in the action bar
+		inflater.inflate(R.menu.profile_manager_actions, menu);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public boolean onOptionsItemSelected(MenuItem item) {
+		switch(item.getItemId()){
+			case R.id.profile_manager_action_add:
+				Intent intent = new Intent(getActivity(), ProfileEditActivity.class);
+				intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+				getActivity().startActivity(intent);
+				return true;
+		}
+
+		return false;
+	}
+}

+ 246 - 0
src/de/tudarmstadt/informatik/hostage/ui/fragment/RecordDetailFragment.java

@@ -0,0 +1,246 @@
+package de.tudarmstadt.informatik.hostage.ui2.fragment;
+
+import java.util.ArrayList;
+import java.util.Date;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.text.format.DateFormat;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+import android.widget.TextView;
+import de.tudarmstadt.informatik.hostage.R;
+import de.tudarmstadt.informatik.hostage.logging.Record;
+import de.tudarmstadt.informatik.hostage.ui2.activity.MainActivity;
+import de.tudarmstadt.informatik.hostage.logging.MessageRecord;
+import de.tudarmstadt.informatik.hostage.persistence.HostageDBOpenHelper;
+
+/**
+ * Displays detailed informations about an record.
+ *
+ * @author Fabio Arnold
+ * @author Alexander Brakowski
+ * @author Julien Clauter
+ */
+public class RecordDetailFragment extends UpNavigatibleFragment {
+
+	/**
+	 * Hold the record of which the detail informations should be shown
+	 */
+	private Record mRecord;
+
+	/**
+	 * The database helper to retrieve data from the database
+	 */
+	private HostageDBOpenHelper mDBOpenHelper;
+
+	/**
+	 * The layout inflater
+	 */
+	private LayoutInflater mInflater;
+
+	/*
+	 * References to the views in the layout
+	 */
+	private View mRootView;
+	private LinearLayout mRecordOverviewConversation;
+	private TextView mRecordDetailsTextSsid;
+	private TextView mRecordDetailsTextBssid;
+	private TextView mRecordDetailsTextRemoteip;
+	private TextView mRecordDetailsTextProtocol;
+	private Button mRecordDeleteButton;
+
+	/**
+	 * Sets the record of which the details should be displayed
+	 * @param rec the record to be used
+	 */
+	public void setRecord(Record rec) {
+		this.mRecord = rec;
+	}
+
+	/**
+	 * Retriebes the record which is used for the display of the detail informations
+	 * @return the record
+	 */
+	public Record getRecord() {
+		return this.mRecord;
+	}
+
+	/**
+	 * Retrieves the id of the layout
+	 * @return the id of the layout
+	 */
+	public int getLayoutId() {
+		return R.layout.fragment_record_detail;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void onCreate(Bundle savedInstanceState) {
+		super.onCreate(savedInstanceState);
+		setHasOptionsMenu(true);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+		super.onCreateView(inflater, container, savedInstanceState);
+
+		mInflater = inflater;
+		getActivity().setTitle(mRecord.getSsid());
+
+		this.mDBOpenHelper = new HostageDBOpenHelper(this.getActivity().getBaseContext());
+
+		this.mRootView = inflater.inflate(this.getLayoutId(), container, false);
+		this.assignViews(mRootView);
+		this.configurateRootView(mRootView);
+
+		return mRootView;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void onStart() {
+		super.onStart();
+
+	}
+
+	/**
+	 * Retrieves all the views from the given view
+	 *
+	 * @param view the layout view
+	 */
+	private void assignViews(View view) {
+		mRecordOverviewConversation = (LinearLayout) view.findViewById(R.id.record_overview_conversation);
+		mRecordDetailsTextSsid = (TextView) view.findViewById(R.id.record_details_text_ssid);
+		mRecordDetailsTextBssid = (TextView) view.findViewById(R.id.record_details_text_bssid);
+		mRecordDetailsTextRemoteip = (TextView) view.findViewById(R.id.record_details_text_remoteip);
+		mRecordDetailsTextProtocol = (TextView) view.findViewById(R.id.record_details_text_protocol);
+		mRecordDeleteButton = (Button) view.findViewById(R.id.record_delete_button);
+	}
+
+
+	/**
+	 * Configures the given view and fills it with the detail information
+	 *
+	 * @param rootView the view to use to display the informations
+	 */
+	private void configurateRootView(View rootView) {
+
+		mRecordDetailsTextBssid.setText(mRecord.getBssid());
+		mRecordDetailsTextSsid.setText(mRecord.getSsid());
+		if (mRecord.getRemoteIP() != null)
+			mRecordDetailsTextRemoteip.setText(mRecord.getRemoteIP() + ":" + mRecord.getRemotePort());
+
+			mRecordDetailsTextProtocol.setText(mRecord.getProtocol());
+
+		ArrayList<Record> conversation = this.mDBOpenHelper.getConversationForAttackID(mRecord.getAttack_id());
+
+		// display the conversation of the attack
+		for (Record r : conversation) {
+			View row;
+
+			String from = r.getLocalIP() == null ? "-" : r.getLocalIP() + ":" + r.getLocalPort();
+			String to = r.getRemoteIP() == null ? "-" : r.getRemoteIP() + ":" + r.getRemotePort();
+
+			if (r.getType() == MessageRecord.TYPE.SEND) {
+				row = mInflater.inflate(R.layout.fragment_record_conversation_sent, null);
+			} else {
+				row = mInflater.inflate(R.layout.fragment_record_conversation_received, null);
+
+				String tmp = from;
+				from = to;
+				to = tmp;
+			}
+
+			TextView conversationInfo = (TextView) row.findViewById(R.id.record_conversation_info);
+			TextView conversationContent = (TextView) row.findViewById(R.id.record_conversation_content);
+			conversationContent.setOnTouchListener(new View.OnTouchListener() {
+				@Override
+				public boolean onTouch(final View v, final MotionEvent motionEvent) {
+					if (v.getId() == R.id.record_conversation_content) {
+						v.getParent().requestDisallowInterceptTouchEvent(true);
+						switch (motionEvent.getAction() & MotionEvent.ACTION_MASK) {
+						case MotionEvent.ACTION_UP:
+							v.getParent().requestDisallowInterceptTouchEvent(false);
+							break;
+						}
+					}
+					return false;
+				}
+			});
+
+			Date date = new Date(r.getTimestamp());
+			conversationInfo.setText(String.format(getString(R.string.record_details_info), from, to, getDateAsString(date), getTimeAsString(date)));
+			if (r.getPacket() != null)
+				conversationContent.setText(r.getPacket());
+
+			mRecordOverviewConversation.addView(row);
+		}
+
+		mRecordDeleteButton.setOnClickListener(new View.OnClickListener() {
+			@Override
+			public void onClick(View v) {
+				Activity activity = getActivity();
+				if (activity == null) {
+					return;
+				}
+				new AlertDialog.Builder(getActivity())
+						.setTitle(android.R.string.dialog_alert_title)
+						.setMessage(R.string.record_details_confirm_delete)
+						.setPositiveButton(R.string.yes,
+								new DialogInterface.OnClickListener() {
+									public void onClick(DialogInterface dialog,
+											int which) {
+										mDBOpenHelper.deleteByAttackID(mRecord.getAttack_id());
+
+										MainActivity.getInstance().navigateBack();
+									}
+								}
+						).setNegativeButton(R.string.no, null)
+						.setIcon(android.R.drawable.ic_dialog_alert).show();
+			}
+		});
+	}
+
+	/*****************************
+	 * 
+	 * Date Transform
+	 * 
+	 * ***************************/
+
+	/**
+	 * Converts the given data to an localized string
+	 *
+	 * @param date the date to convert
+	 * @return the converted date as an string
+	 */
+	private String getDateAsString(Date date) {
+		return DateFormat.getDateFormat(getActivity()).format(date);
+	}
+
+	/**
+	 * Converts the given date to an localized time
+	 *
+	 * @param date the date to convert
+	 * @return the converted time as an string
+	 */
+	private String getTimeAsString(Date date) {
+		return DateFormat.getTimeFormat(getActivity()).format(date);
+	}
+}

+ 1438 - 0
src/de/tudarmstadt/informatik/hostage/ui/fragment/RecordOverviewFragment.java

@@ -0,0 +1,1438 @@
+package de.tudarmstadt.informatik.hostage.ui2.fragment;
+
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.FragmentManager;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ExpandableListView;
+import android.widget.ImageButton;
+import android.widget.ProgressBar;
+import android.widget.Toast;
+
+import com.google.android.gms.maps.model.LatLng;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Random;
+
+import de.tudarmstadt.informatik.hostage.R;
+import de.tudarmstadt.informatik.hostage.logging.AttackRecord;
+import de.tudarmstadt.informatik.hostage.logging.LogExport;
+import de.tudarmstadt.informatik.hostage.logging.MessageRecord;
+import de.tudarmstadt.informatik.hostage.logging.NetworkRecord;
+import de.tudarmstadt.informatik.hostage.logging.Record;
+import de.tudarmstadt.informatik.hostage.persistence.HostageDBOpenHelper;
+import de.tudarmstadt.informatik.hostage.sync.bluetooth.BluetoothSyncActivity;
+import de.tudarmstadt.informatik.hostage.sync.nfc.NFCSync;
+import de.tudarmstadt.informatik.hostage.sync.tracing.TracingSyncActivity;
+import de.tudarmstadt.informatik.hostage.ui2.activity.MainActivity;
+import de.tudarmstadt.informatik.hostage.ui2.adapter.RecordListAdapter;
+import de.tudarmstadt.informatik.hostage.ui2.dialog.ChecklistDialog;
+import de.tudarmstadt.informatik.hostage.ui2.dialog.DateTimeDialogFragment;
+import de.tudarmstadt.informatik.hostage.ui2.model.ExpandableListItem;
+import de.tudarmstadt.informatik.hostage.ui2.model.LogFilter;
+import de.tudarmstadt.informatik.hostage.ui2.model.LogFilter.SortType;
+import de.tudarmstadt.informatik.hostage.ui2.popup.AbstractPopup;
+import de.tudarmstadt.informatik.hostage.ui2.popup.AbstractPopupItem;
+import de.tudarmstadt.informatik.hostage.ui2.popup.SimplePopupItem;
+import de.tudarmstadt.informatik.hostage.ui2.popup.SimplePopupTable;
+import de.tudarmstadt.informatik.hostage.ui2.popup.SplitPopupItem;
+
+public class RecordOverviewFragment extends UpNavigatibleFragment implements ChecklistDialog.ChecklistDialogListener, DateTimeDialogFragment.DateTimeDialogFragmentListener {
+
+	static final String FILTER_MENU_TITLE_BSSID = MainActivity.getContext().getString(R.string.BSSID);
+	static final String FILTER_MENU_TITLE_ESSID = MainActivity.getContext().getString(R.string.ESSID);
+	static final String FILTER_MENU_TITLE_PROTOCOLS = MainActivity.getContext().getString(R.string.rec_protocol);
+	static final String FILTER_MENU_TITLE_TIMESTAMP_BELOW = MainActivity.getContext().getString(
+			R.string.rec_latest);
+	static final String FILTER_MENU_TITLE_TIMESTAMP_ABOVE = MainActivity.getContext().getString(
+			R.string.rec_earliest);
+	static final String FILTER_MENU_TITLE_SORTING = MainActivity.getContext().getString(R.string.rec_sortby);
+	static final String FILTER_MENU_TITLE_REMOVE = MainActivity.getContext().getString(R.string.rec_reset_filter);
+    static final String FILTER_MENU_TITLE_GROUP = MainActivity.getContext().getString(
+			R.string.rec_group_by);
+    static final String FILTER_MENU_POPUP_TITLE = MainActivity.getContext().getString(
+			R.string.rec_filter_by);
+
+    static final int DEFAULT_GROUPING_KEY_INDEX = 0;
+
+    private boolean wasBelowTimePicker;
+
+    private LogFilter filter;
+    private boolean showFilterButton;
+    private View rootView;
+
+    private int mListPosition = -1;
+    private int mItemPosition = -1;
+
+    public String groupingKey;
+
+    private ExpandableListView expListView;
+    private ProgressBar spinner;
+
+    private Toast noDataNotificationToast;
+
+    HostageDBOpenHelper dbh;
+
+    private String sectionToOpen = "";
+    private ArrayList<Integer> openSections;
+
+	private SharedPreferences pref;
+
+    Thread loader;
+
+
+    /* DATE CONVERSION STUFF*/
+    static final DateFormat localisedDateFormatter = DateFormat.getDateInstance(DateFormat.SHORT, Locale.getDefault());
+    // DATE WHICH PATTERN
+    static final String localDatePattern  = ((SimpleDateFormat)localisedDateFormatter).toLocalizedPattern();
+    static final String groupingDatePattern  = "MMMM yyyy";
+
+    // INSERT HERE YOUR DATE PATERN
+    static final SimpleDateFormat groupingDateFormatter = new SimpleDateFormat(groupingDatePattern);
+    static final Calendar calendar = Calendar.getInstance();
+
+    // DATE STRINGS
+    static final String TODAY = MainActivity.getInstance().getResources().getString( R.string.TODAY);
+    static final String YESTERDAY = MainActivity.getInstance().getResources().getString( R.string.YESTERDAY);
+
+
+
+
+    /**
+     * Constructor
+     */
+    public RecordOverviewFragment(){}
+
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setHasOptionsMenu(true);
+    }
+
+    @Override
+	public View onCreateView(LayoutInflater inflater, ViewGroup container,
+             Bundle savedInstanceState) {
+
+		setHasOptionsMenu(true);
+		getActivity().setTitle(getResources().getString(R.string.drawer_records));
+
+		dbh = new HostageDBOpenHelper(this.getActivity().getBaseContext());
+	    pref = PreferenceManager.getDefaultSharedPreferences(getActivity());
+
+	    // Get the message from the intent
+
+
+        if (this.filter == null){
+            Intent intent = this.getActivity().getIntent();
+            LogFilter filter = intent.getParcelableExtra(LogFilter.LOG_FILTER_INTENT_KEY);
+
+            if(filter == null){
+                this.clearFilter();
+            } else {
+                this.filter = filter;
+            }
+        }
+
+        if (this.groupingKey == null) this.groupingKey = this.groupingTitles().get(DEFAULT_GROUPING_KEY_INDEX);
+
+	    this.setShowFilterButton(!this.filter.isNotEditable());
+
+		View rootView = inflater.inflate(this.getLayoutId(), container, false);
+        this.rootView = rootView;
+		ExpandableListView mylist = (ExpandableListView) rootView.findViewById(R.id.loglistview);
+
+        this.spinner =(ProgressBar) rootView.findViewById(R.id.progressBar1);
+        this.spinner.setVisibility(View.GONE);
+
+		this.expListView = mylist;
+
+        this.initialiseListView();
+
+        ImageButton filterButton = (ImageButton) rootView.findViewById(R.id.FilterButton);
+        filterButton.setOnClickListener(new View.OnClickListener() {
+            public void onClick(View v) {
+            	RecordOverviewFragment.this.openFilterPopupMenuOnView(v);
+            }
+        });
+        filterButton.setVisibility(this.showFilterButton? View.VISIBLE : View.INVISIBLE);
+
+        ImageButton sortButton = (ImageButton) rootView.findViewById(R.id.SortButton);
+        sortButton.setOnClickListener(new View.OnClickListener() {
+            public void onClick(View v) {
+                // Open SortMenu
+                RecordOverviewFragment.this.openSortingDialog();
+            }
+        });
+
+        ImageButton groupButton = (ImageButton) rootView.findViewById(R.id.GroupButton);
+        groupButton.setOnClickListener(new View.OnClickListener() {
+            public void onClick(View v) {
+                // Open SortMenu
+                RecordOverviewFragment.this.openGroupingDialog();
+            }
+        });
+
+		return rootView;
+	 }
+
+
+    /**Initialises the expandable list view in a backgorund thread*/
+    private void initialiseListView(){
+        if (loader != null) loader.interrupt();
+
+        this.spinner.setVisibility(View.VISIBLE);
+
+        loader = new Thread(new Runnable(){
+
+            private void updateUI(final RecordListAdapter currentAdapter)
+            {
+                if(loader.isInterrupted()){
+                    return;
+                }
+                Activity activity = RecordOverviewFragment.this.getActivity();
+
+                if (activity != null){
+                    activity.runOnUiThread(new Runnable() {
+                        @Override
+                        public void run() {
+                            RecordOverviewFragment.this.expListView.setAdapter(currentAdapter);
+                            // Update view and remove loading spinner etc...
+                            RecordListAdapter adapter = (RecordListAdapter) RecordOverviewFragment.this.expListView.getExpandableListAdapter();
+
+                            if (adapter != null){
+                                adapter.notifyDataSetChanged();
+
+                                if (adapter.getGroupCount() >= 1){
+                                    RecordOverviewFragment.this.expListView.expandGroup(DEFAULT_GROUPING_KEY_INDEX);
+                                } else {
+                                    RecordOverviewFragment.this.setSectionToOpen(RecordOverviewFragment.this.sectionToOpen);
+                                }
+                            }
+
+                            if (RecordOverviewFragment.this.openSections != null && RecordOverviewFragment.this.openSections.size() != 0){
+                                for (int i = 0; i < RecordOverviewFragment.this.openSections.size(); i++){
+                                    int index = RecordOverviewFragment.this.openSections.get(i);
+                                    RecordOverviewFragment.this.expListView.expandGroup(index);
+                                }
+                            } else {
+                                RecordOverviewFragment.this.openSections = new ArrayList<Integer>();
+                            }
+
+                            if (mListPosition != -1 && mItemPosition != -1)
+                                RecordOverviewFragment.this.expListView.setSelectedChild(mListPosition, mItemPosition, true);
+
+                            mListPosition = -1;
+                            mItemPosition = -1;
+                            registerListClickCallback(RecordOverviewFragment.this.expListView);
+                            RecordOverviewFragment.this.spinner.setVisibility(View.GONE);
+                            RecordOverviewFragment.this.actualiseFilterButton();
+                            RecordOverviewFragment.this.showEmptyDataNotification();
+                        }
+                    });
+                }
+            }
+
+            private RecordListAdapter doInBackground()
+            {
+                return populateListViewFromDB(RecordOverviewFragment.this.expListView);
+            }
+
+            @Override
+            public void run()
+            {
+                //RecordOverviewFragment.this.addRecordToDB(40, 10, 4);
+                updateUI(doInBackground());
+            }
+
+        });
+
+        loader.start();
+
+        this.actualiseFilterButton();
+    }
+
+
+    /**
+    *  Returns the Fragment layout ID
+    *  @return int The fragment layout ID
+    * */
+    public int getLayoutId(){
+        return R.layout.fragment_record_list;
+    }
+
+    /**
+    * Gets called if the user clicks on item in the filter menu.
+    *
+    * @param  item {@link AbstractPopupItem AbstractPopupItem }
+    * */
+	public void onFilterMenuItemSelected(AbstractPopupItem item) {
+		String title = item.getTitle();
+
+        if (item instanceof SplitPopupItem){
+            SplitPopupItem splitItem = (SplitPopupItem)item;
+            if (splitItem.wasRightTouch){
+                this.openTimestampToFilterDialog();
+            } else {
+                this.openTimestampFromFilterDialog();
+            }
+            return;
+        }
+
+        if (title != null){
+            if(title.equals(FILTER_MENU_TITLE_BSSID)){
+                this.openBSSIDFilterDialog();
+            }
+            if(title.equals(FILTER_MENU_TITLE_ESSID)){
+                this.openESSIDFilterDialog();
+            }
+            if(title.equals(FILTER_MENU_TITLE_PROTOCOLS)){
+                this.openProtocolsFilterDialog();
+            }
+            if(title.equals(FILTER_MENU_TITLE_SORTING)){
+                this.openSortingDialog();
+            }
+            if(title.equals(FILTER_MENU_TITLE_REMOVE)){
+                this.clearFilter();
+                this.actualiseListViewInBackground();
+            }
+            if(title.equals(FILTER_MENU_TITLE_TIMESTAMP_BELOW)){
+                this.openTimestampToFilterDialog();
+            }
+            if(title.equals(FILTER_MENU_TITLE_TIMESTAMP_ABOVE)){
+                this.openTimestampFromFilterDialog();
+            }
+        }
+		//return super.onOptionsItemSelected(item);
+	}
+
+
+
+    @Override
+    public void onStart() {
+        super.onStart();
+        if (this.expListView.getExpandableListAdapter() != null){
+            if (this.expListView.getExpandableListAdapter().getGroupCount() == 1){
+                this.expListView.expandGroup(0);
+            } else {
+                this.setSectionToOpen(this.sectionToOpen);
+            }
+        }
+
+    }
+
+	@Override
+	public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+		// Inflate the menu items for use in the action bar
+		inflater.inflate(R.menu.records_overview_actions, menu);
+	}
+
+	@Override
+	public boolean onOptionsItemSelected(MenuItem item) {
+		switch (item.getItemId()) {
+			case R.id.records_action_synchronize:
+
+				AlertDialog.Builder builder = new AlertDialog.Builder(this.getActivity());
+				builder.setTitle(MainActivity.getInstance().getString(R.string.rec_sync_rec));
+				builder.setItems(new String[]{
+						MainActivity.getInstance().getString(R.string.rec_via_bt),
+						MainActivity.getInstance().getString(R.string.rec_via_nfc),
+						MainActivity.getInstance().getString(R.string.rec_via_online)
+				}, new DialogInterface.OnClickListener() {
+					@Override
+					public void onClick(DialogInterface dialog, int position) {
+						switch(position){
+							case 0:
+								getActivity().startActivity(new Intent(getActivity(), BluetoothSyncActivity.class));
+								break;
+							case 1:
+								getActivity().startActivity(new Intent(getActivity(), NFCSync.class));
+								break;
+
+							case 2:
+								getActivity().startActivity(new Intent(getActivity(), TracingSyncActivity.class));
+								break;
+						}
+					}
+				});
+				builder.create();
+				builder.show();
+
+
+				return true;
+			case R.id.records_action_export:
+				AlertDialog.Builder builderExport = new AlertDialog.Builder(getActivity());
+				builderExport.setTitle(MainActivity.getInstance().getString(R.string.rec_choose_export_format));
+				builderExport.setItems(R.array.format, new DialogInterface.OnClickListener() {
+					@Override
+					public void onClick(DialogInterface dialog, int position) {
+						//RecordOverviewFragment.this.exportDatabase(position);
+						Intent intent = new Intent(getActivity(), LogExport.class);
+						intent.setAction(LogExport.ACTION_EXPORT_DATABASE);
+						intent.putExtra(LogExport.FORMAT_EXPORT_DATABASE, position);
+
+						RecordOverviewFragment.this.getActivity().startService(intent);
+					}
+				});
+				builderExport.create();
+				builderExport.show();
+
+				return true;
+		}
+
+		return false;
+	}
+
+	/*****************************
+	 *
+	 * 			Public API
+	 *
+	 * ***************************/
+
+	/**
+	 * Group records by SSID and expand given SSID
+	 *
+	 * @param SSID the SSID
+	 */
+	public void showDetailsForSSID(Context context,  String SSID) {
+		Log.e("RecordOverviewFragment", "Implement showDetailsForSSID!!");
+        this.clearFilter();
+        int ESSID_INDEX = 2;
+        ArrayList<String> ssids = new ArrayList<String>();
+        this.sectionToOpen = SSID;
+        this.groupingKey = this.groupingTitles().get(ESSID_INDEX);
+  	}
+
+
+	/*****************************
+	 *
+	 *          ListView Stuff
+	 *
+	 * ***************************/
+
+    /**
+    *  Reloads the data in the ExpandableListView for the given filter object.
+    *  @param  mylist {@link ExpandableListView ExpandableListView}
+    * */
+	private RecordListAdapter populateListViewFromDB(ExpandableListView mylist) {
+        ArrayList<String> groupTitle = new ArrayList<String>();
+
+        HashMap<String, ArrayList<ExpandableListItem>> sectionData = this.fetchDataForFilter(this.filter, groupTitle);
+
+        RecordListAdapter adapter = null;
+        if (mylist.getAdapter() != null && mylist.getAdapter() instanceof RecordListAdapter){
+            adapter = (RecordListAdapter) mylist.getAdapter();
+            adapter.setData(sectionData);
+            adapter.setSectionHeader(groupTitle);
+        } else {
+            adapter = new RecordListAdapter( RecordOverviewFragment.this.getApplicationContext(), groupTitle, sectionData);
+        }
+
+        return adapter;
+	}
+
+    private HashMap<String, ArrayList<ExpandableListItem>> fetchDataForFilter(LogFilter filter, ArrayList<String> groupTitle){
+        HashMap<String, ArrayList<ExpandableListItem>> sectionData = new HashMap<String, ArrayList<ExpandableListItem>>();
+
+        ArrayList<Record> data = dbh.getRecordsForFilter(filter == null ? this.filter : filter);
+
+        // Adding Items to ListView
+        String keys[] = new String[] { RecordOverviewFragment.this.getString(R.string.RecordBSSID), RecordOverviewFragment.this.getString(R.string.RecordSSID), RecordOverviewFragment.this.getString(R.string.RecordProtocol), RecordOverviewFragment.this.getString(R.string.RecordTimestamp)};
+        int ids[] = new int[] {R.id.RecordTextFieldBSSID, R.id.RecordTextFieldSSID, R.id.RecordTextFieldProtocol, R.id.RecordTextFieldTimestamp };
+
+        HashMap<String, Integer> mapping = new HashMap<String, Integer>();
+        int i = 0;
+        for(String key : keys){
+            mapping.put(key, ids[i]);
+            i++;
+        }
+
+        if (groupTitle == null){
+            groupTitle = new ArrayList<String>();
+        } else {
+            groupTitle.clear();
+        }
+
+
+        for (Record val : data) {
+            // DO GROUPING IN HERE
+            HashMap<String, String> map = new HashMap<String, String>();
+            map.put(RecordOverviewFragment.this.getString(R.string.RecordBSSID), val.getBssid());
+            map.put(RecordOverviewFragment.this.getString(R.string.RecordSSID), val.getSsid());
+            map.put(RecordOverviewFragment.this.getString(R.string.RecordProtocol), val.getProtocol());
+            map.put(RecordOverviewFragment.this.getString(R.string.RecordTimestamp),
+                    RecordOverviewFragment.this.getDateAsString(val.getTimestamp()));
+
+            ExpandableListItem item = new ExpandableListItem();
+            item.setData(map);
+
+            item.setId_Mapping(mapping);
+
+            item.setTag(val.getAttack_id());
+
+            String groupID = RecordOverviewFragment.this.getGroupValue(val);
+
+            ArrayList<ExpandableListItem> items = sectionData.get(groupID);
+            if (items == null) {
+                items = new ArrayList<ExpandableListItem>();
+                sectionData.put(groupID, items);
+                groupTitle.add(groupID);
+            }
+
+
+            items.add(item);
+        }
+
+        if (this.groupingKey.equals(this.groupingTitles().get(DEFAULT_GROUPING_KEY_INDEX))){
+            Collections.sort(groupTitle,new DateStringComparator());
+        } else {
+            Collections.sort(groupTitle, new Comparator<String>() {
+                @Override
+                public int compare(String s1, String s2) {
+                    return s1.compareToIgnoreCase(s2);
+                }
+            });
+        }
+
+        return sectionData;
+    }
+
+    /**
+     * The DateStringComparator compares formatted date strings by converting the into date.
+     * This class  is mainly used for grouping the records by their timestamp.
+     */
+    class DateStringComparator implements Comparator<String>
+    {
+        public int compare(String lhs, String rhs)
+        {
+            Date date1 = RecordOverviewFragment.this.convertStringToDate(lhs);
+            Date date2 = RecordOverviewFragment.this.convertStringToDate(rhs);
+
+            return date2.compareTo(date1);
+        }
+    }
+
+    /**
+     * Actualises the list in a background thread
+     */
+    private void actualiseListViewInBackground(){
+        if (loader != null && loader.isAlive()) loader.interrupt();
+
+        loader = null;
+
+        this.spinner.setVisibility(View.VISIBLE);
+        this.actualiseFilterButton();
+
+        loader = new Thread(new Runnable() {
+            @Override
+            public void run() {
+                this.runOnUiThread(this.doInBackground());
+            }
+
+            private RecordListAdapter doInBackground(){
+                return RecordOverviewFragment.this.populateListViewFromDB(RecordOverviewFragment.this.expListView);
+            }
+
+            private void runOnUiThread(final RecordListAdapter adapter){
+                Activity actv = RecordOverviewFragment.this.getActivity();
+                if (actv != null){
+                    actv.runOnUiThread(new Runnable() {
+                        @Override
+                        public void run() {
+                            this.actualiseUI();
+                        }
+                        private void actualiseUI(){
+                            if (adapter != null){
+                                RecordOverviewFragment.this.expListView.setAdapter(adapter);
+                                adapter.notifyDataSetChanged();
+                                RecordOverviewFragment.this.spinner.setVisibility(View.GONE);
+                            }
+                            RecordOverviewFragment.this.showEmptyDataNotification();
+                        }
+                    });
+                }
+            }
+        });
+        loader.start();
+    }
+
+    /**
+     * Shows a small toast if the data to show is empty (no records).
+     */
+    private void showEmptyDataNotification(){
+        if (RecordOverviewFragment.this.noDataNotificationToast == null){
+            RecordOverviewFragment.this.noDataNotificationToast =  Toast.makeText(getApplicationContext(), R.string.no_data_notification, Toast.LENGTH_SHORT);
+        }
+        RecordListAdapter adapter = (RecordListAdapter) RecordOverviewFragment.this.expListView.getExpandableListAdapter();
+
+        if (this.getFilterButton().getVisibility() == View.VISIBLE && this.filter.isSet()){
+            this.noDataNotificationToast.setText(R.string.no_data_notification);
+        } else {
+            this.noDataNotificationToast.setText(R.string.no_data_notification_no_filter);
+        }
+        if (adapter == null || adapter.getData().isEmpty())
+            RecordOverviewFragment.this.noDataNotificationToast.show();
+
+    }
+
+    /**This will open a section in the ExpandableListView with the same title as the parameter s.
+    *
+    * @param s String (the section title to open)
+    *
+    * */
+    private void setSectionToOpen(String s){
+        this.sectionToOpen = s;
+        if (this.sectionToOpen != null && this.sectionToOpen.length() != 0){
+            if (this.getGroupTitles().contains(this.sectionToOpen)){
+                int section = this.getGroupTitles().indexOf(this.sectionToOpen);
+                this.expListView.expandGroup(section);
+                this.sectionToOpen = "";
+            }
+        }
+    }
+
+    /**
+    * Returns the base context.
+    * @return Context baseContext
+    * */
+	private Context getBaseContext(){
+		return this.getActivity().getBaseContext();
+	}
+
+    /**Returns the application context.
+    * @return Context application context
+    * */
+	private Context getApplicationContext(){
+		return this.getActivity().getApplicationContext();
+	}
+
+    /**Sets the list view listener on the given ExpandableListView.
+    *
+    * @param mylist  {@link ExpandableListView ExpandableListView }
+    * */
+	private void registerListClickCallback(ExpandableListView mylist) {
+        mylist.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
+            @Override
+            public boolean onChildClick(ExpandableListView expandableListView, View view, int i, int i2, long l) {
+                RecordListAdapter adapter = (RecordListAdapter)expandableListView.getExpandableListAdapter();
+
+                ExpandableListItem item = (ExpandableListItem)adapter.getChild(i,i2);
+
+                mListPosition = i;
+                mItemPosition = i2;
+	            HostageDBOpenHelper dbh = new HostageDBOpenHelper(getBaseContext());
+                Record rec = dbh.getRecordOfAttackId((int) item.getTag());
+                RecordOverviewFragment.this.pushRecordDetailViewForRecord(rec);
+                return true;
+            }
+        });
+        mylist.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener() {
+            @Override
+            public void onGroupExpand(int i) {
+                RecordOverviewFragment.this.openSections.add(new Integer(i));
+            }
+        });
+        mylist.setOnGroupCollapseListener(new ExpandableListView.OnGroupCollapseListener() {
+            @Override
+            public void onGroupCollapse(int i) {
+                RecordOverviewFragment.this.openSections.remove(new Integer(i));
+            }
+        });
+	}
+
+
+
+	/*****************************
+	 *
+	 *          Date Transformation / Conversion
+	 *
+	 * ***************************/
+
+
+    /**Returns the localised date format for the given timestamp
+    * @param timeStamp long */
+	@SuppressLint("SimpleDateFormat")
+	private String getDateAsString(long timeStamp) {
+        Date date = (new Date(timeStamp));
+        try {
+            DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, Locale.getDefault());
+			return formatter.format(date);
+		} catch (Exception ex) {
+			return "---";
+		}
+	}
+
+    /**
+     * Returns the timestamp in a own format.
+     * Depending on the returned format the grouping by timestamp will change.
+     *
+     * e.g.
+     * If you return a DateAsMonth formatted Date the records will be mapped by their month and year.
+     * If you return the a DateAsDay formatted Date the records will be mapped by their day, month and year.
+     * and so on...
+     *
+     * @param timestamp long
+     * @return formatted date String
+     */
+    public String getFormattedDateForGrouping(long timestamp) {
+
+        // DECIDE WHICH KIND OF FORMAT SHOULD BE USED
+        // MONTH FORMAT
+        String date = this.getDateAsMonthString(timestamp);
+        // DAY FORMAT
+        //String date = this.getDateAsDayString(timestamp);
+
+        return date;
+    }
+
+    /**Returns a date as a formated string
+     * @param timestamp date
+     * @return String date format is localised*/
+    @SuppressLint("SimpleDateFormat")
+    private String getDateAsDayString(long timestamp) {
+        try {
+            Date netDate = (new Date(timestamp));
+            String dateString;
+
+            long date = this.dayMilliseconds(timestamp);
+
+            if(this.todayMilliseconds() == date ){
+                dateString = TODAY;
+            }else if(this.yesterdayMilliseconds() == date ){
+                dateString = YESTERDAY;
+            } else {
+                dateString = localisedDateFormatter.format(netDate);
+            }
+            return dateString;
+
+        } catch (Exception ex) {
+            return "---";
+        }
+    }
+
+    /**
+     * Converts a formatted DateString into a date.
+     * @param dateString String
+     * @return Date
+     */
+    private Date convertStringToDate(String dateString){
+        if (dateString != null && dateString.length() != 0){
+            SimpleDateFormat dateFormat = groupingDateFormatter; //new SimpleDateFormat(localDatePattern);
+            Date date;
+            try {
+                if (dateString.equals(TODAY)){
+                    long millisec = RecordOverviewFragment.this.todayMilliseconds();
+                    date = new Date(millisec);
+                } else if (dateString.equals(YESTERDAY)){
+                    long millisec = RecordOverviewFragment.this.yesterdayMilliseconds();
+                    date = new Date(millisec);
+                } else {
+                    date = dateFormat.parse(dateString);
+                }
+                return date;
+
+            } catch (java.text.ParseException e ) {
+                date = new Date(0);
+                return date;
+            }
+        } else {
+            return new Date(0);
+        }
+    }
+
+    /**
+     * Returns the milliseconds for the day today (not the time).
+     * @return long
+     */
+    private long todayMilliseconds(){
+        Date current = new Date();
+        calendar.setTimeInMillis(current.getTime());
+        int day = calendar.get(Calendar.DATE);
+        int month = calendar.get(Calendar.MONTH);
+        int year = calendar.get(Calendar.YEAR);
+
+        calendar.set(year, month, day, 0,0,0);
+
+        long milli = calendar.getTimeInMillis();
+
+        Date today = new Date(milli);
+
+        return (milli / (long) 1000) * (long) 1000;
+    }
+
+    /**
+     * Returns the milliseconds for the day yesterday (not the time).
+     * @return long
+     */
+    private long yesterdayMilliseconds(){
+        Date current = new Date();
+        calendar.setTimeInMillis(current.getTime());
+        int day = calendar.get(Calendar.DATE);
+        int month = calendar.get(Calendar.MONTH);
+        int year = calendar.get(Calendar.YEAR);
+
+        calendar.set(year, month, day, 0,0,0);
+
+        calendar.add(Calendar.DATE, -1);
+
+        long milli = calendar.getTimeInMillis();
+
+        Date today = new Date(milli);
+
+        return (milli / (long) 1000) * (long) 1000;
+    }
+
+    /**
+     * returns just the date not the time of a date.
+     * @param date Date
+     * @return long
+     */
+    private long dayMilliseconds(long date){
+        //Date current = new Date();
+        calendar.setTimeInMillis(date);
+        int day = calendar.get(Calendar.DATE);
+        int month = calendar.get(Calendar.MONTH);
+        int year = calendar.get(Calendar.YEAR);
+
+        calendar.set(year, month, day, 0,0,0);
+
+        long milli = calendar.getTimeInMillis();
+
+        Date test = new Date(milli);
+
+        return (milli / (long) 1000) * (long) 1000;
+    }
+
+    /**Returns a date as a formated string
+     * @param timeStamp date
+     * @return String date format is localised*/
+    @SuppressLint("SimpleDateFormat")
+    private String getDateAsMonthString(long timeStamp) {
+        try {
+            Date netDate = (new Date(timeStamp));
+            return groupingDateFormatter.format(netDate);
+        } catch (Exception ex) {
+            return "xx";
+        }
+    }
+
+
+	/*****************************
+	 *
+	 *          Getter / Setter
+	 *
+	 * ***************************/
+
+	public boolean isShowFilterButton() {
+		return showFilterButton;
+	}
+
+	public void setShowFilterButton(boolean showFilterButton) {
+		this.showFilterButton = showFilterButton;
+	}
+
+    /**
+     * Set the group key for grouping the records.
+     * All possible grouping keys are:
+     * R.string.date,
+     * R.string.rec_protocol,
+     * R.string.ESSID,
+     * R.string.BSSID
+     * @param key String
+     */
+    public void setGroupKey(String key){
+        this.groupingKey = key;
+    }
+
+    public void setFilter(LogFilter filter){
+        this.filter = filter;
+    }
+
+
+	/*****************************
+	 *
+	 *          Open Dialog Methods
+	 *
+	 * ***************************/
+
+    /**Opens the grouping dialog*/
+    private void openGroupingDialog(){
+        ChecklistDialog newFragment = new ChecklistDialog(FILTER_MENU_TITLE_GROUP, this.groupingTitles(), this.selectedGroup(), false , this);
+        newFragment.show(this.getActivity().getFragmentManager(), FILTER_MENU_TITLE_GROUP);
+    }
+
+    /**opens the bssid filter dialog*/
+	private void openBSSIDFilterDialog(){
+		ChecklistDialog newFragment = new ChecklistDialog(FILTER_MENU_TITLE_BSSID,this.bssids(), this.selectedBSSIDs(), true , this);
+	    newFragment.show(this.getActivity().getFragmentManager(), FILTER_MENU_TITLE_BSSID);
+	}
+
+    /**opens the essid filter dialog*/
+	private void openESSIDFilterDialog(){
+		ChecklistDialog newFragment = new ChecklistDialog(FILTER_MENU_TITLE_ESSID,this.essids(), this.selectedESSIDs(), true , this);
+	    newFragment.show(this.getActivity().getFragmentManager(), FILTER_MENU_TITLE_ESSID);
+	}
+
+    /**opens the protocol filter dialog*/
+	private void openProtocolsFilterDialog(){
+		ChecklistDialog newFragment = new ChecklistDialog(FILTER_MENU_TITLE_PROTOCOLS,this.protocolTitles(), this.selectedProtocols(), true , this);
+	    newFragment.show(this.getActivity().getFragmentManager(), FILTER_MENU_TITLE_PROTOCOLS);
+	}
+
+    /**opens the timestamp filter dialog (minimal timestamp required)*/
+	private void openTimestampFromFilterDialog(){
+		this.wasBelowTimePicker = false;
+		DateTimeDialogFragment newFragment = new DateTimeDialogFragment(this.getActivity());
+	    newFragment.show(this.getActivity().getFragmentManager(), FILTER_MENU_TITLE_SORTING);
+        if (this.filter.aboveTimestamp != Long.MIN_VALUE)newFragment.setDate(this.filter.aboveTimestamp);
+	}
+
+    /**opens time timestamp filter dialog (maximal timestamp required)*/
+	private void openTimestampToFilterDialog(){
+		this.wasBelowTimePicker = true;
+		DateTimeDialogFragment newFragment = new DateTimeDialogFragment(this.getActivity());
+	    newFragment.show(this.getActivity().getFragmentManager(), FILTER_MENU_TITLE_SORTING);
+        if (this.filter.belowTimestamp != Long.MAX_VALUE) newFragment.setDate(this.filter.belowTimestamp);
+    }
+
+    /**opens the sorting dialog*/
+	private void openSortingDialog(){
+		ChecklistDialog newFragment = new ChecklistDialog(FILTER_MENU_TITLE_SORTING,this.sortTypeTiles(), this.selectedSorttype(), false , this);
+	    newFragment.show(this.getActivity().getFragmentManager(), FILTER_MENU_TITLE_SORTING);
+	}
+
+    /*****************************
+     *
+     *          Grouping Stuff
+     *
+     * ***************************/
+
+    /**returns the group title for the given record. Uses the groupingKey to decied which value of the record should be used.
+    * @param  rec {@link Record Record }
+    * @return String grouptitle*/
+    public String getGroupValue(Record rec){
+        int index = this.groupingTitles().indexOf(this.groupingKey);
+        switch (index){
+            case 1:
+                return rec.getProtocol();
+            case 2:
+                return rec.getSsid();
+            case 3:
+                return rec.getBssid();
+            case 0:
+                return this.getFormattedDateForGrouping(rec.getTimestamp());
+            default:
+                return this.getFormattedDateForGrouping(rec.getTimestamp());
+        }
+    }
+
+    /**Returns the Group titles for the specified grouping key. e.g. groupingKey is "ESSID" it returns all available essids.
+    * @return ArrayList<String> grouptitles*/
+    public List<String> getGroupTitles(){
+        int index = this.groupingTitles().indexOf(this.groupingKey);
+        switch (index){
+            case 1:
+                return this.protocolTitles();
+            case 2:
+                return this.essids();
+            case 3:
+                return this.bssids();
+            case 0:
+            default:
+                RecordListAdapter adapter = (RecordListAdapter) this.expListView.getExpandableListAdapter();
+                if (adapter != null){
+                    return adapter.getSectionHeaders();
+                }
+                return new ArrayList<String>();
+            }
+    }
+
+
+	/*****************************
+	 *
+	 *          Filter Stuff
+	 *
+	 * ***************************/
+
+    /**Returns the FilterButton.
+     * @return ImageButton filterButton*/
+    private ImageButton getFilterButton(){
+        return (ImageButton) this.rootView.findViewById(R.id.FilterButton);
+    }
+
+    /**Opens the filter menu on a anchor view. The filter menu will always be on top of the anchor.
+    * @param  v View the anchorView*/
+	private void openFilterPopupMenuOnView(View v){
+
+        SimplePopupTable filterMenu = new SimplePopupTable(this.getActivity(), new AbstractPopup.OnPopupItemClickListener() {
+            public void onItemClick(Object ob) {
+                if (ob instanceof  AbstractPopupItem){
+                    AbstractPopupItem item = (AbstractPopupItem) ob;
+                    RecordOverviewFragment.this.onFilterMenuItemSelected(item);
+                }
+            }
+        });
+        filterMenu.setTitle(FILTER_MENU_POPUP_TITLE);
+		for(String title : RecordOverviewFragment.this.filterMenuTitles()){
+            AbstractPopupItem item = null;
+            if (title.equals(FILTER_MENU_TITLE_TIMESTAMP_BELOW)) continue;
+            if (title.equals(FILTER_MENU_TITLE_TIMESTAMP_ABOVE)){
+                item = new SplitPopupItem(this.getActivity());
+                item.setValue(SplitPopupItem.RIGHT_TITLE, FILTER_MENU_TITLE_TIMESTAMP_BELOW);
+                item.setValue(SplitPopupItem.LEFT_TITLE, FILTER_MENU_TITLE_TIMESTAMP_ABOVE);
+                if (this.filter.hasBelowTimestamp()){
+                    item.setValue(SplitPopupItem.RIGHT_SUBTITLE, this.getDateAsString(this.filter.belowTimestamp));
+                }
+                if (this.filter.hasAboveTimestamp()){
+                    item.setValue(SplitPopupItem.LEFT_SUBTITLE, this.getDateAsString(this.filter.aboveTimestamp));
+                }
+            } else {
+                item = new SimplePopupItem(this.getActivity());
+                item.setTitle(title);
+                ((SimplePopupItem)item).setSelected(this.isFilterSetForTitle(title));
+            }
+
+            filterMenu.addItem(item);
+		}
+		filterMenu.showOnView(v);
+	}
+
+    /**Returns true  if the filter object is set for the given title otherwise false. e.g. the filter object has protocols,
+    * so the method will return for the title FILTER_MENU_TITLE_PROTOCOLS TRUE.
+    * @param  title String
+    * @return boolean value
+    * */
+    private boolean isFilterSetForTitle(String title){
+        if (title.equals(FILTER_MENU_TITLE_BSSID)){
+            return this.filter.hasBSSIDs();
+        }
+        if (title.equals(FILTER_MENU_TITLE_ESSID)){
+            return this.filter.hasESSIDs();
+        }
+        if (title.equals(FILTER_MENU_TITLE_PROTOCOLS)){
+            return this.filter.hasProtocols();
+        }
+        if (title.equals(FILTER_MENU_TITLE_TIMESTAMP_BELOW)){
+            return this.filter.hasBelowTimestamp();
+        }
+        if (title.equals(FILTER_MENU_TITLE_TIMESTAMP_ABOVE)){
+            return this.filter.hasAboveTimestamp();
+        }
+        return false;
+    }
+
+    /**clears the filter. Does not invoke populatelistview!*/
+	private void clearFilter(){
+    	if(filter == null) this.filter = new LogFilter();
+    	this.filter.clear();
+	}
+
+    /**Returns all grouping titles.
+    * @return ArrayList<String> tiles*/
+    public ArrayList<String> groupingTitles(){
+        ArrayList<String> titles = new ArrayList<String>();
+        titles.add(MainActivity.getContext().getString(R.string.date));
+        titles.add(MainActivity.getContext().getString(R.string.rec_protocol));
+        titles.add(MainActivity.getContext().getString(R.string.ESSID));
+        titles.add(MainActivity.getContext().getString(R.string.BSSID));
+        return titles;
+    }
+    /**
+     * Returns a bool array. This array is true at the index of the groupingKey in groupingTitles(), otherwise false.
+    * @return boolean[] selection
+    * */
+    public boolean[] selectedGroup(){
+        ArrayList<String> groups = this.groupingTitles();
+        boolean[] selected = new boolean[groups.size()];
+        int i = 0;
+        for(String group : groups){
+            selected[i] =(group.equals(this.groupingKey));
+            i++;
+        }
+        return selected;
+    }
+
+    /**Returns all protocol titles / names.
+    * @return ArrayList<String> protocolTitles
+    * */
+	public ArrayList<String> protocolTitles(){
+		ArrayList<String> titles = new ArrayList<String>();
+		for (String protocol : this.getResources().getStringArray(
+				R.array.protocols)) {
+			titles.add(protocol);
+		}
+
+		titles.add("PORTSCAN");
+		return titles;
+	}
+    /**Return a boolean array of the selected / filtered protocols. If the filter object has
+    * an protocol from the protocolTitles() array, the index of it will be true, otherwise false.
+    * @return boolean[] protocol selection
+    * */
+	public boolean[] selectedProtocols(){
+		ArrayList<String> protocols = this.protocolTitles();
+		boolean[] selected = new boolean[protocols.size()];
+
+		int i = 0;
+		for(String protocol : protocols){
+			selected[i] =(this.filter.protocols.contains(protocol));
+			i++;
+		}
+		return selected;
+	}
+
+    /**
+    * Returns the Sorttype Titles
+    * @return ArayList<String> Sort type titles
+    * */
+	public ArrayList<String> sortTypeTiles(){
+		ArrayList<String> titles = new ArrayList<String>();
+		titles.add(MainActivity.getContext().getString(R.string.rec_time));
+		titles.add(MainActivity.getContext().getString(R.string.rec_protocol));
+        titles.add(MainActivity.getContext().getString(R.string.ESSID));
+        titles.add(MainActivity.getContext().getString(R.string.BSSID));
+		return titles;
+	}
+    /**
+    * Returns an boolean array. The array is true at the index of the selected sort type..
+    * The index of the selected sort type is the same index in the sortTypeTiles array.
+    * @return boolean array, length == sortTypeTiles().length
+    * */
+	public boolean[] selectedSorttype(){
+		ArrayList<String> types = this.sortTypeTiles();
+		boolean[] selected = new boolean[types.size()];
+		int i = 0;
+		for(String sorttype : types){
+			selected[i] =(this.filter.sorttype.toString().equals(sorttype));
+			i++;
+		}
+		return selected;
+	}
+
+    /**
+    * Returns all unique bssids.
+    * @return ArrayList<String>
+    * */
+	public ArrayList<String> bssids(){
+		ArrayList<String> records = dbh.getUniqueBSSIDRecords();
+		return records;
+	}
+    /**
+    * Returns an boolean array. The array is true at the indices of the selected bssids.
+    * The index of the selected bssid is the same index in the bssids() array.
+    * @return boolean array, length == bssids().length
+    * */
+	public boolean[] selectedBSSIDs(){
+		ArrayList<String> bssids = this.bssids();
+		boolean[] selected = new boolean[bssids.size()];
+
+		int i = 0;
+		for(String bssid : bssids){
+			selected[i] =(this.filter.BSSIDs.contains(bssid));
+			i++;
+		}
+		return selected;
+	}
+
+    /**
+    * Returns all unique essids.
+    * @return ArrayList<String>
+    * */
+	public ArrayList<String> essids(){
+		ArrayList<String> records = dbh.getUniqueESSIDRecords();
+		return records;
+	}
+    /**
+    * Returns an boolean array. The array is true at the indices of the selected essids.
+    * The index of the selected essid is the same index in the essids() array.
+    * @return boolean array, length == essids().length
+    * */
+	public boolean[] selectedESSIDs(){
+		ArrayList<String> essids = this.essids();
+		boolean[] selected = new boolean[essids.size()];
+
+		int i = 0;
+		for(String essid : essids){
+			selected[i] =(this.filter.ESSIDs.contains(essid));
+			i++;
+		}
+		return selected;
+	}
+
+    /**
+     * Returns all filter menu titles.
+     * @return ArrayList<String>
+     * */
+	private ArrayList<String> filterMenuTitles(){
+		ArrayList<String> titles = new ArrayList<String>();
+		titles.add(FILTER_MENU_TITLE_BSSID);
+		titles.add(FILTER_MENU_TITLE_ESSID);
+		titles.add(FILTER_MENU_TITLE_PROTOCOLS);
+		titles.add(FILTER_MENU_TITLE_TIMESTAMP_ABOVE);
+		titles.add(FILTER_MENU_TITLE_TIMESTAMP_BELOW);
+        if (this.filter.isSet())titles.add(FILTER_MENU_TITLE_REMOVE);
+		return titles;
+	}
+
+
+	/*****************************
+	 *
+	 *          Listener Actions
+	 *
+	 * ***************************/
+
+    /**
+     * Will be called if the users selects a timestamp.
+     * @param  dialog {@link DateTimeDialogFragment DateTimeDialogFragment }
+     * */
+	public void onDateTimePickerPositiveClick(DateTimeDialogFragment dialog) {
+		if(this.wasBelowTimePicker){
+			this.filter.setBelowTimestamp(dialog.getDate());
+		} else {
+			this.filter.setAboveTimestamp(dialog.getDate());
+		}
+        this.actualiseListViewInBackground();
+        this.actualiseFilterButton();
+    }
+    /**
+     * Will be called if the users cancels a timestamp selection.
+     * @param dialog  {@link DateTimeDialogFragment DateTimeDialogFragment }
+     * */
+	public void onDateTimePickerNegativeClick(DateTimeDialogFragment dialog) {
+		if(this.wasBelowTimePicker){
+			this.filter.setBelowTimestamp(Long.MAX_VALUE);
+		} else {
+			this.filter.setAboveTimestamp(Long.MIN_VALUE);
+		}
+        this.actualiseListViewInBackground();
+        this.actualiseFilterButton();
+    }
+
+    /**
+     * Will be called if the users clicks the positiv button on a ChechlistDialog.
+     * @param  dialog  {@link ChecklistDialog ChecklistDialog }
+     */
+	public void onDialogPositiveClick(ChecklistDialog dialog) {
+		String title = dialog.getTitle();
+		if(title.equals(FILTER_MENU_TITLE_BSSID)){
+            ArrayList<String> titles =dialog.getSelectedItemTitles();
+            if (titles.size() == this.bssids().size()){
+                this.filter.setBSSIDs(new ArrayList<String>());
+            } else {
+                this.filter.setBSSIDs(titles);
+            }
+		}
+		if(title.equals(FILTER_MENU_TITLE_ESSID)){
+            ArrayList<String> titles =dialog.getSelectedItemTitles();
+            if (titles.size() == this.essids().size()){
+                this.filter.setESSIDs(new ArrayList<String>());
+            } else {
+                this.filter.setESSIDs(titles);
+            }
+		}
+		if(title.equals(FILTER_MENU_TITLE_PROTOCOLS)){
+            ArrayList<String> protocols = dialog.getSelectedItemTitles();
+            if (protocols.size() == this.protocolTitles().size()){
+                this.filter.setProtocols(new ArrayList<String>());
+            } else {
+			    this.filter.setProtocols(dialog.getSelectedItemTitles());
+            }
+		}
+		if(title.equals(FILTER_MENU_TITLE_SORTING)){
+			ArrayList<String> titles = dialog.getSelectedItemTitles();
+            if (titles.size() == 0) return;
+            // ALWAYS GET THE FIRST ELEMENT (SHOULD BE ALWAYS ONE)
+            String t = titles.get(0);
+			int sortType = this.sortTypeTiles().indexOf(t);
+			this.filter.setSorttype(SortType.values()[sortType]);
+		}
+        if (title.equals(FILTER_MENU_TITLE_GROUP)){
+            ArrayList<String> titles = dialog.getSelectedItemTitles();
+            if (titles.size() == 0) return;
+            // ALWAYS GET THE FIRST ELEMENT (SHOULD BE ALWAYS ONE)
+            this.groupingKey =  titles.get(0);
+        }
+        this.actualiseListViewInBackground();
+
+        this.actualiseFilterButton();
+	}
+
+    /**Paints the filter button if the current filter object is set.*/
+    private void actualiseFilterButton(){
+        if (this.filter.isSet() ){
+            ImageButton filterButton = this.getFilterButton();
+            if (filterButton != null){
+                filterButton.setImageResource(R.drawable.ic_filter_pressed);
+                filterButton.invalidate();
+            }
+        } else {
+            ImageButton filterButton = this.getFilterButton();
+            if (filterButton != null){
+                filterButton.setImageResource(R.drawable.ic_filter);
+                filterButton.invalidate();
+            }
+        }
+    }
+
+    /**
+     * Will be called if the users clicks the negativ button on a ChechlistDialog.
+     * @param  dialog  {@link ChecklistDialog ChecklistDialog }
+     */
+	public void onDialogNegativeClick(ChecklistDialog dialog) {}
+
+
+	/*****************************
+	 *
+	 *          TEST
+	 *
+	 * ***************************/
+
+    /**
+    * This will clear the database at first and than add new attacks.
+    * @param createNetworks number of networks to create
+    * @param attacksPerNetwork maximal number of attack per network
+    * @param maxMessagePerAttack maximal number of messages per attack
+    * */
+	private void addRecordToDB( int createNetworks, int attacksPerNetwork, int maxMessagePerAttack) {
+        if ((dbh.getRecordCount() > 0)) dbh.clearData();
+
+		Calendar cal = Calendar.getInstance();
+
+		int maxProtocolsIndex = this.getResources().getStringArray(
+				R.array.protocols).length;
+
+		Random random = new Random();
+
+		LatLng tudarmstadtLoc = new LatLng(49.86923, 8.6632768);
+
+
+		final double ssidRadius = 0.1;
+		final double bssidRadius = 0.004;
+
+        int attackId = 0;
+
+        for (int numOfNetworks = 0; numOfNetworks < createNetworks; numOfNetworks++){
+            String ssidName = "WiFi" + ((numOfNetworks) + 1);
+            String bssidName = "127.0.0." + ((numOfNetworks) + 1);
+
+            int protocolIndex = numOfNetworks % maxProtocolsIndex;
+            String protocolName = this.getResources().getStringArray(
+                    R.array.protocols)[protocolIndex];
+
+            int numOfAttackPerNetwork = (Math.abs(random.nextInt()) % Math.max(1, attacksPerNetwork + 1));
+
+            NetworkRecord network = new NetworkRecord();
+            network.setBssid(bssidName);
+            network.setSsid(ssidName);
+
+            LatLng ssidLocation = new LatLng(tudarmstadtLoc.latitude - ssidRadius + 2.0 * ssidRadius * Math.random(), tudarmstadtLoc.longitude - ssidRadius + 2.0 * ssidRadius * Math.random());
+            double latitude = ssidLocation.latitude - bssidRadius + 2.0 * bssidRadius * Math.random();
+            double longitude = ssidLocation.longitude - bssidRadius + 2.0 * bssidRadius * Math.random();
+
+            long timestamp = cal.getTimeInMillis();
+            network.setTimestampLocation(timestamp);
+            network.setLongitude(longitude);
+            network.setLatitude(latitude);
+            network.setAccuracy(0.f);
+
+            dbh.updateNetworkInformation(network);
+
+            // ATTACKS PER NETWORK
+            for (int attackNumber = 0; attackNumber < numOfAttackPerNetwork; attackNumber++) {
+
+                int numRecordsPerAttack = (Math.abs(random.nextInt()) % (Math.max( maxMessagePerAttack, 1))) + 1;
+
+                if (maxMessagePerAttack <= 0) numRecordsPerAttack = 0;
+
+                /* ADD A ATTACK*/
+                AttackRecord attack = new AttackRecord();
+                attack.setAttack_id(attackId);
+
+                attack.setBssid(bssidName);
+
+                attack.setProtocol(protocolName);
+                attack.setLocalIP(bssidName);
+
+
+                dbh.addAttackRecord(attack);
+
+                // MESSAGE PER ATTACK
+                for (int messageID = attackId; messageID < attackId + numRecordsPerAttack; messageID++) {
+                    MessageRecord message = new MessageRecord();
+                    message.setId(messageID);
+                    message.setAttack_id(attackId);
+
+                    // GO BACK IN TIME
+                    message.setTimestamp(cal.getTimeInMillis()
+                            - ((messageID * 60 * 60 * 24) * 1000) + (1000 * ((messageID - attackId) + 1)));
+
+                    if ((messageID - attackId) % 2 == 0){
+                        message.setType(MessageRecord.TYPE.RECEIVE);
+                    } else {
+                        message.setType(MessageRecord.TYPE.SEND);
+                    }
+                    message.setPacket("");
+
+                    dbh.addMessageRecord(message);
+                }
+
+                attackId+=numRecordsPerAttack;
+            }
+
+        }
+
+//        int countAllLogs = dbh.getAllRecords().size();
+//        int countRecords = dbh.getRecordCount();
+//        int countAttacks = dbh.getAttackCount();
+//
+//        if ((countRecords == 0)) {
+//            Record rec = dbh.getRecordOfAttackId(0);
+//            Record rec2 = dbh.getRecord(0);
+//
+//            System.out.println("" + "Could not create logs!");
+//        }
+
+    }
+
+
+    /**Navigation. Shows the record detail view for the given record
+    * @param  record  {@link Record Record } to show
+    * */
+    private void pushRecordDetailViewForRecord(Record record){
+
+        FragmentManager fm = this.getActivity().getFragmentManager();
+
+        if (fm != null){
+            RecordDetailFragment newFragment = new RecordDetailFragment();
+            newFragment.setRecord(record);
+
+            newFragment.setUpNavigatible(true);
+
+            MainActivity.getInstance().injectFragment(newFragment);
+
+        }
+
+    }
+}

+ 322 - 0
src/de/tudarmstadt/informatik/hostage/ui/fragment/ServicesFragment.java

@@ -0,0 +1,322 @@
+package de.tudarmstadt.informatik.hostage.ui2.fragment;
+
+import java.util.ArrayList;
+
+import android.app.AlertDialog;
+import android.app.Fragment;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.support.v4.content.LocalBroadcastManager;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.CompoundButton;
+import android.widget.ListView;
+import android.widget.Switch;
+import android.widget.TextView;
+import de.tudarmstadt.informatik.hostage.Handler;
+import de.tudarmstadt.informatik.hostage.R;
+import de.tudarmstadt.informatik.hostage.commons.HelperUtils;
+import de.tudarmstadt.informatik.hostage.model.Profile;
+import de.tudarmstadt.informatik.hostage.persistence.ProfileManager;
+import de.tudarmstadt.informatik.hostage.persistence.HostageDBOpenHelper;
+import de.tudarmstadt.informatik.hostage.ui2.activity.MainActivity;
+import de.tudarmstadt.informatik.hostage.ui2.adapter.ServicesListAdapter;
+import de.tudarmstadt.informatik.hostage.ui2.model.ServicesListItem;
+
+/**
+ * @author Daniel Lazar
+ * @created 05.02.14
+ * Fragment that displays a switch for every protocol.
+ * Also it can de-/activate every protocol by using this switch.
+ */
+public class ServicesFragment extends TrackerFragment {
+    private Switch mServicesSwitchService;
+    private TextView mServicesTextName;
+
+    private View rootView;
+
+    private CompoundButton.OnCheckedChangeListener switchChangeListener = null;
+
+    private BroadcastReceiver mReceiver;
+
+    private ServicesListAdapter adapter;
+
+    private ArrayList<ServicesListItem> protocolList;
+
+    private HostageDBOpenHelper dbh = new HostageDBOpenHelper(MainActivity.getContext());
+
+    private String[] protocols;
+
+    private SharedPreferences mConnectionInfo;
+
+    private boolean mReceiverRegistered = false;
+
+    private Profile mProfile;
+    private Integer[] mGhostPorts;
+
+    public ServicesFragment() {
+    }
+
+    /**
+     * assign views which are not asynchronously loaded
+     */
+    private void assignViews() {
+        mServicesSwitchService = (Switch) rootView.findViewById(R.id.service_switch_connection);
+        mServicesTextName = (TextView) rootView.findViewById(R.id.services_text_name);
+
+        rootView.findViewById(R.id.services_button_connection_info).setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                ConnectionInfoDialogFragment connectionInfoDialogFragment = new ConnectionInfoDialogFragment();
+                connectionInfoDialogFragment.show(getFragmentManager().beginTransaction(), connectionInfoDialogFragment.getTag());
+            }
+        });
+
+    }
+
+    /**
+     * updates the user interface
+     * in detail: the main switch and the textField mServicesTextName
+     */
+    public void updateUI() {
+        //SK: Temp bugfix
+        //if (!HelperUtils.isNetworkAvailable(getActivity())) {
+        if (!HelperUtils.isWifiConnected(getActivity())) {
+            if(!MainActivity.getInstance().getHostageService().hasRunningListeners()) {
+                mServicesSwitchService.setOnCheckedChangeListener(null);
+                setStateNotConnected();
+                setStateNotActive();
+                mServicesSwitchService.setOnCheckedChangeListener(switchChangeListener);
+            }
+            else{
+                mServicesSwitchService.setOnCheckedChangeListener(null);
+                setStateNotConnected();
+                mServicesSwitchService.setChecked(true);
+                mServicesSwitchService.setOnCheckedChangeListener(switchChangeListener);
+            }
+        } else {
+            if (MainActivity.getInstance().getHostageService().hasRunningListeners()) {
+                setStateActive();
+            }
+            String ssid = mConnectionInfo.getString(getString(R.string.connection_info_ssid), "");
+
+            mServicesTextName.setText(ssid.substring(1,ssid.length()-1));
+        }
+
+    }
+
+    /**
+     * register a broadcast receiver if not already registered
+     * and also update the number of attacks per protocol
+     */
+    private void registerBroadcastReceiver() {
+        if (!mReceiverRegistered) {
+            mReceiver = new BroadcastReceiver() {
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    String sender = intent.getStringExtra("SENDER");
+                    String[] values = intent.getStringArrayExtra("VALUES");
+
+                    if (sender.equals(Handler.class.getName()) && values[0].equals(getString(R.string.broadcast_started))) {
+                        for (ServicesListItem item : protocolList) {
+                            if (item.protocol.equals(values[1])) {
+                                item.attacks = dbh.numBssidSeen(item.protocol, mConnectionInfo.getString(getString(R.string.connection_info_bssid), null));
+                            }
+                        }
+                    }
+
+                    if (!MainActivity.getInstance().getHostageService().hasRunningListeners()) {
+                        setStateNotActive();
+                    } else {
+                        setStateActive();
+                    }
+                    updateUI();
+                    adapter.notifyDataSetChanged();
+                }
+            };
+
+            LocalBroadcastManager.getInstance(getActivity()).registerReceiver(mReceiver, new IntentFilter(getString(R.string.broadcast)));
+            this.mReceiverRegistered = true;
+        }
+    }
+
+
+    /**
+     * most important method of this class
+     *
+     * @param inflater the inflater
+     * @param container the container
+     * @param savedInstanceState the saved instance state
+     * @return rootView
+     */
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+
+        super.onCreateView(inflater, container, savedInstanceState);
+
+        rootView = inflater.inflate(R.layout.fragment_services, container, false);
+        assignViews();
+
+        protocols = getResources().getStringArray(R.array.protocols);
+        mConnectionInfo = getActivity().getSharedPreferences(getString(R.string.connection_info), Context.MODE_PRIVATE);
+
+        updateUI();
+
+        ListView list = (ListView) rootView.findViewById(R.id.services_list_view);
+
+        protocolList = new ArrayList<ServicesListItem>();
+        int i = 0;
+        for (String protocol : protocols) {
+            protocolList.add(new ServicesListItem(protocol));
+            protocolList.get(i).attacks = dbh.numBssidSeen(protocolList.get(i).protocol, mConnectionInfo.getString(getString(R.string.connection_info_bssid), null));
+            i++;
+        }
+
+        mServicesSwitchService = (Switch) rootView.findViewById(R.id.service_switch_connection);
+
+        if (switchChangeListener == null) {
+            switchChangeListener = new CompoundButton.OnCheckedChangeListener() {
+                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+                    mProfile = ProfileManager.getInstance().getCurrentActivatedProfile();
+                    //SK: Temp bugfix
+                        //if (!HelperUtils.isNetworkAvailable(getActivity())) {
+                    if (!HelperUtils.isWifiConnected(getActivity())) {
+                            if(!MainActivity.getInstance().getHostageService().hasRunningListeners()) {
+                                new AlertDialog.Builder(getActivity())
+                                        .setTitle(R.string.information)
+                                        .setMessage(R.string.wifi_not_connected_msg)
+                                        .setPositiveButton(android.R.string.ok,
+                                                new DialogInterface.OnClickListener() {
+                                                    public void onClick(DialogInterface dialog, int which) {
+
+                                                    }
+                                                }
+                                        )
+                                        .setIcon(android.R.drawable.ic_dialog_info)
+                                        .show();
+                                if(mServicesSwitchService.isChecked()) {
+                                    setStateNotActive();
+                                }
+                                setStateNotConnected();
+                            }
+                            else{
+                                setStateActive();
+                            }
+                    } else {
+                        if (MainActivity.getInstance().isServiceBound()) {
+                            if (isChecked) {
+                                for (String protocol : protocols) {
+                                    if (!protocol.equals("GHOST")) {
+                                        if (!MainActivity.getInstance().getHostageService().isRunning(protocol)) {
+                                            MainActivity.getInstance().getHostageService().startListener(protocol);
+                                        }
+                                    } else {
+                                        if (mProfile.mGhostActive) {
+
+                                            mGhostPorts = mProfile.getGhostPorts();
+                                            if (mGhostPorts.length != 0) {
+                                                for (Integer port : mGhostPorts) {
+                                                    if (!MainActivity.getInstance().getHostageService().isRunning("GHOST", port)) {
+                                                        MainActivity.getInstance().getHostageService().startListener("GHOST", port);
+                                                    }
+                                                }
+                                            }
+
+
+                                        }
+                                    }
+                                }
+                                setStateActive();
+                            } else{
+                                MainActivity.getInstance().getHostageService().stopListeners();
+                                MainActivity.getInstance().stopAndUnbind();
+                                setStateNotActive();
+                            }
+                        }
+                    }
+                }
+
+            };
+        }
+        mServicesSwitchService.setOnCheckedChangeListener(switchChangeListener);
+
+        adapter = new ServicesListAdapter(getActivity().getBaseContext(), protocolList);
+        adapter.setActivity(this.getActivity(), this.mServicesSwitchService, this.switchChangeListener);
+        list.setAdapter(adapter);
+
+        registerBroadcastReceiver();
+
+        return rootView;
+
+    }
+
+    /**
+     * called on start of this fragment.
+     * registers broadcast receiver and binds change listener to main switch
+     */
+    @Override
+    public void onStart() {
+        super.onStart();
+        registerBroadcastReceiver();
+        mServicesSwitchService.setOnCheckedChangeListener(switchChangeListener);
+    }
+
+    /**
+     * unregister the broadcast receiver if a receiver is already registered
+     */
+    private void unregisterBroadcastReceiver() {
+        if (mReceiverRegistered) {
+            LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(mReceiver);
+            this.mReceiverRegistered = false;
+        }
+    }
+
+    /**
+     * sets main switch to true
+     */
+    private void setStateActive() {
+            mServicesSwitchService.setChecked(true);
+    }
+
+    /**
+     * sets text of text field to not connected, if the device is not connected to a network
+     */
+    private void setStateNotConnected() {
+        mServicesTextName.setText(R.string.not_connected);
+    }
+
+    /**
+     * sets main switch to false
+     */
+    private void setStateNotActive() {
+        if (mServicesSwitchService.isChecked()) {
+            mServicesSwitchService.setChecked(false);
+        }
+    }
+
+    /**
+     * overrides onStop
+     * unloads the ChangeListener
+     */
+    @Override
+    public void onStop() {
+        super.onStop();
+        mServicesSwitchService.setOnCheckedChangeListener(null);
+    }
+
+    /**
+     * overrides onDestroy
+     * unregisters broadcast receiver, when destroyed
+     */
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        unregisterBroadcastReceiver();
+    }
+}

+ 283 - 0
src/de/tudarmstadt/informatik/hostage/ui/fragment/SettingsFragment.java

@@ -0,0 +1,283 @@
+package de.tudarmstadt.informatik.hostage.ui2.fragment;
+
+import android.app.AlertDialog;
+import android.app.DownloadManager;
+import android.app.DownloadManager.Query;
+import android.app.DownloadManager.Request;
+import android.app.Fragment;
+import android.app.FragmentManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.SharedPreferences;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Environment;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.channels.FileChannel;
+import java.util.zip.ZipInputStream;
+
+import de.tudarmstadt.informatik.hostage.Hostage;
+import de.tudarmstadt.informatik.hostage.R;
+import de.tudarmstadt.informatik.hostage.system.Decompress;
+import de.tudarmstadt.informatik.hostage.system.Device;
+import de.tudarmstadt.informatik.hostage.ui2.activity.MainActivity;
+
+/**
+ * Creates the view to edit the preferences of the app and shows the porthack and rooted state of the device
+ *
+ * @author Alexander Brakowski
+ * @created 24.02.14 23:37
+ */
+public class SettingsFragment extends UpNavigatibleFragment {
+
+	/**
+	 * {@inheritDoc}
+	 */
+
+    private long enqueue;
+    private DownloadManager dm;
+    private BroadcastReceiver receiver;
+    /**
+     * Hold the shared preferences for the app
+     */
+    private SharedPreferences mSharedPreferences;
+
+    public void portbinderAlert(final SharedPreferences.Editor editor){
+        new AlertDialog.Builder(getActivity())
+                .setTitle(R.string.information)
+                .setMessage(R.string.no_portbinder_msg)
+                .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+                    public void onClick(DialogInterface dialog, int which) {
+
+                    }
+                })
+                .setNegativeButton(R.string.no_thanks, new DialogInterface.OnClickListener() {
+                            public void onClick(DialogInterface dialog, int which) {
+                                //never show this to users again
+                                if (editor != null) {
+                                    editor.putBoolean("donotshowagain", true);
+                                    editor.commit(); //commit if any changes on the preferences
+                                }
+                            }
+                        }
+                )
+                .setNeutralButton(R.string.how, new DialogInterface.OnClickListener() {
+
+                    public void onClick(DialogInterface dialog, int which) {
+                        dialog.dismiss();
+                        final AlertDialog alert;
+
+                        new AlertDialog.Builder(getActivity())
+                                .setTitle(R.string.portbinder)
+                                .setMessage(R.string.helpPortbinder)
+                                .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+                                    public void onClick(DialogInterface dialog, int which) {
+
+                                    }
+                                })
+                                .setNegativeButton(R.string.portbinder_website, new DialogInterface.OnClickListener() {
+                                    public void onClick(DialogInterface dialog, int which) {
+
+                                        Uri uri = Uri.parse("https://www.tk.informatik.tu-darmstadt.de/de/research/secure-smart-infrastructures/hostage/");
+                                        Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+                                        startActivity(intent);
+
+                                    }
+                                })
+                                        //Testing automated installation of portbinder
+                                .setNeutralButton(R.string.help_me, new DialogInterface.OnClickListener() {
+                                    public void onClick(DialogInterface dialog, int which) {
+                                        dialog.dismiss();
+
+                                        new AlertDialog.Builder(getActivity())
+                                                .setTitle(R.string.portbinder)
+                                                .setMessage(R.string.confirm_msg)
+                                                .setPositiveButton(R.string.confirm, new DialogInterface.OnClickListener() {
+                                                    public void onClick(DialogInterface dialog, int which) {
+                                                        //Download Portbinder
+                                                        dm = (DownloadManager) getActivity().getSystemService(Context.DOWNLOAD_SERVICE);
+
+                                                        //Identify architecture
+                                                        String arch = System.getProperty("os.arch"); //get the device architecture
+                                                        String fileName = "";
+
+                                                        //selecting necessary PortBinder architecture
+                                                        if (arch.matches("arm.*"))      //arm
+                                                            fileName = "bind-arm.zip";
+                                                        else if (arch.matches("x86"))   //x86
+                                                            fileName = "bind-x86.zip";
+                                                        else if (arch.matches("mips"))  //mips
+                                                            fileName = "bind-mips.zip";
+
+                                                        Uri uri = Uri.parse("https://www.tk.informatik.tu-darmstadt.de/fileadmin/user_upload/Group_TK/"+fileName);
+
+                                                        if (!fileName.isEmpty()) //As long we have a valid string (non-empty)
+                                                        {
+                                                            Request request = new Request(uri)
+                                                                    .setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName);
+                                                            enqueue = dm.enqueue(request);
+                                                        }
+                                                        else {
+                                                            //report to user of an unknown architecture
+                                                        }
+
+                                                    }
+                                                })
+                                                .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
+                                                    public void onClick(DialogInterface dialog, int which) {
+
+
+
+                                                    }
+                                                })
+                                                .setIcon(android.R.drawable.ic_dialog_alert).show();
+                                                ;
+
+                                    }
+                                })
+                                .setIcon(android.R.drawable.ic_dialog_info).show();
+
+                    }
+                })
+                .setIcon(android.R.drawable.ic_dialog_info).show();
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+		super.onCreateView(inflater, container, savedInstanceState);
+		getActivity().setTitle(getResources().getString(R.string.drawer_settings));
+		View v = inflater.inflate(R.layout.fragment_settings, container, false);
+
+        mSharedPreferences = getActivity().getSharedPreferences(getString(R.string.shared_preference_path), Hostage.MODE_PRIVATE);
+        final SharedPreferences.Editor editor = mSharedPreferences.edit();
+
+		final TextView rootedText = (TextView) v.findViewById(R.id.settings_device_rooted);
+		final TextView porthackText = (TextView) v.findViewById(R.id.settings_porthack_installed);
+
+		if (Device.isRooted()) {
+			rootedText.setText(R.string.yes);
+			rootedText.setTextColor(getResources().getColor(R.color.holo_dark_green));
+		} else {
+			rootedText.setText(R.string.no);
+			rootedText.setTextColor(getResources().getColor(R.color.holo_red));
+		}
+
+		if (Device.isPorthackInstalled()) {
+			porthackText.setText(R.string.yes);
+			porthackText.setTextColor(getResources().getColor(R.color.holo_dark_green));
+		} else {
+
+            if (!mSharedPreferences.getBoolean("donotshowagain", false))
+                portbinderAlert(editor);
+
+			porthackText.setText(R.string.no);
+			porthackText.setTextColor(getResources().getColor(R.color.holo_red));
+		}
+
+        //Handle if a download 'may' be needed
+        receiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                String action = intent.getAction();
+                if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(action)) {
+                    long downloadId = intent.getLongExtra(
+                            DownloadManager.EXTRA_DOWNLOAD_ID, 0);
+                    Query query = new Query();
+                    query.setFilterById(enqueue);
+                    Cursor c = dm.query(query);
+                    if (c.moveToFirst()) {
+                        int columnIndex = c
+                                .getColumnIndex(DownloadManager.COLUMN_STATUS);
+                        if (DownloadManager.STATUS_SUCCESSFUL == c
+                                .getInt(columnIndex)) {
+
+                            String downloadFile = c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME));
+                            String makeWritable[]= {"su","-c","chmod","777","/data/local"}; //change permission to allow rw access from x only
+                            String allowExec[]= {"su","-c","chmod","711","/data/local/bind"}; //change permission to allow x access
+                            String revert[]= {"su","-c","chmod","751","/data/local"}; //change permission back to x only
+
+                            try {
+                                //Chmod the local directory for write access
+                                Process process = Runtime.getRuntime().exec(makeWritable);
+                                process.waitFor();
+
+                                Log.d("portbinder:","Changing permission on /data/local to allow write access");
+
+                                //Decompressing downloaded zip to local directory
+                                Decompress dwnld = new Decompress(downloadFile,"/data/local/" );
+                                dwnld.unzip();
+                                Log.v("portbinder:","Decompressing downloaded file");
+
+                                //Chmod the Portbinder to allow it to be executable
+                                process = Runtime.getRuntime().exec(allowExec);
+                                process.waitFor();
+                                Log.v("portbinder:","Changing permission on /data/local/bind to allow the binary to be executed");
+
+                                //Chmod the local directory to back to non-read/write access
+                                process = Runtime.getRuntime().exec(revert);
+                                process.waitFor();
+                                Log.v("portbinder:","Changing permission on /data/local back to no-write access");
+
+
+                            } catch (IOException e) {
+                                e.printStackTrace();
+                            } catch (InterruptedException e) {
+                                e.printStackTrace();
+                            }
+
+                            if(Device.updatePorthack()) //if successful
+                            {
+                                porthackText.setText(R.string.yes);
+                                porthackText.setTextColor(getResources().getColor(R.color.holo_dark_green));
+                            }
+
+                        }
+                    }
+                }
+            }
+        };
+
+        getActivity().registerReceiver(receiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
+
+            return v;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void onViewCreated(View view, Bundle savedInstanceState) {
+		super.onViewCreated(view, savedInstanceState);
+
+		FragmentManager manager = this.getFragmentManager();
+		manager.beginTransaction().replace(R.id.settings_fragment_container, new PreferenceHostageFrament()).commit();
+	}
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        getActivity().unregisterReceiver(receiver);
+
+    }
+
+}

+ 1846 - 0
src/de/tudarmstadt/informatik/hostage/ui/fragment/StatisticsFragment.java

@@ -0,0 +1,1846 @@
+package de.tudarmstadt.informatik.hostage.ui2.fragment;
+
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.app.Fragment;
+import android.app.FragmentManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ImageButton;
+import android.widget.LinearLayout;
+import android.widget.ListView;
+import android.widget.ProgressBar;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.echo.holographlibrary.Bar;
+import com.echo.holographlibrary.BarGraph;
+import com.echo.holographlibrary.Line;
+import com.echo.holographlibrary.LineGraph;
+import com.echo.holographlibrary.LinePoint;
+import com.echo.holographlibrary.PieGraph;
+import com.echo.holographlibrary.PieSlice;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.HashMap;
+
+import de.tudarmstadt.informatik.hostage.R;
+import de.tudarmstadt.informatik.hostage.logging.Record;
+import de.tudarmstadt.informatik.hostage.persistence.HostageDBOpenHelper;
+import de.tudarmstadt.informatik.hostage.ui2.model.LogFilter;
+import de.tudarmstadt.informatik.hostage.ui2.activity.MainActivity;
+import de.tudarmstadt.informatik.hostage.ui2.adapter.StatisticListAdapter;
+import de.tudarmstadt.informatik.hostage.ui2.dialog.ChecklistDialog;
+import de.tudarmstadt.informatik.hostage.ui2.dialog.DateTimeDialogFragment;
+import de.tudarmstadt.informatik.hostage.ui2.helper.ColorSequenceGenerator;
+import de.tudarmstadt.informatik.hostage.ui2.model.PlotComparisonItem;
+import de.tudarmstadt.informatik.hostage.ui2.popup.AbstractPopup;
+import de.tudarmstadt.informatik.hostage.ui2.popup.AbstractPopupItem;
+import de.tudarmstadt.informatik.hostage.ui2.popup.SimplePopupItem;
+import de.tudarmstadt.informatik.hostage.ui2.popup.SimplePopupTable;
+import de.tudarmstadt.informatik.hostage.ui2.popup.SplitPopupItem;
+
+/**
+ * Created by Julien on 16.02.14.
+ */
+public class StatisticsFragment extends TrackerFragment implements ChecklistDialog.ChecklistDialogListener, DateTimeDialogFragment.DateTimeDialogFragmentListener {
+
+    static final String FILTER_MENU_TITLE_BSSID = "BSSID";
+    static final String FILTER_MENU_TITLE_ESSID = "ESSID";
+    static final String FILTER_MENU_TITLE_PROTOCOLS = MainActivity.getContext().getString(R.string.stats_protocols);
+    static final String FILTER_MENU_TITLE_PROTOCOL = MainActivity.getContext().getString(R.string.rec_protocol);
+    static final String FILTER_MENU_TITLE_TIMESTAMP_BELOW = MainActivity.getContext().getString(R.string.rec_latest);
+    static final String FILTER_MENU_TITLE_TIMESTAMP_ABOVE = MainActivity.getContext().getString(R.string.rec_earliest);
+
+    static final String FILTER_MENU_TITLE_REMOVE = MainActivity.getContext().getString(R.string.rec_reset_filter);
+    static final String FILTER_MENU_POPUP_TITLE = MainActivity.getContext().getString(R.string.rec_filter_by);
+
+
+    static final String MENU_TITLE_PROTOCOLS = MainActivity.getContext().getString(
+			R.string.stats_protocols);
+    static final String MENU_TITLE_NETWORK = MainActivity.getContext().getString(
+			R.string.stats_networks);
+    static final String MENU_TITLE_ATTACKS = MainActivity.getContext().getString(
+			R.string.stats_attacks);
+
+    static final String MENU_POPUP_TITLE = MainActivity.getContext().getString(
+			R.string.stats_visualize);
+
+    static final String CHART_TYPE_TITLE_BAR = MainActivity.getContext().getString(
+			R.string.stats_bar_plot);
+    static final String CHART_TYPE_TITLE_PIE = MainActivity.getContext().getString(R.string.stats_pie_plot);
+    static final String CHART_TYPE_TITLE_LINE = MainActivity.getContext().getString(R.string.stats_line_plot);
+
+    //static final String DIALOG_PROTOCOLS_TITLE = MainActivity.getContext().getString(R.string.stats_select_protocol_data);
+    static final String DIALOG_NETWORK_TITLE = MainActivity.getContext().getString(R.string.stats_select_network_data);
+    static final String DIALOG_ATTACK_TITLE = MainActivity.getContext().getString(R.string.stats_select_attack_data);
+
+    static  final String COMPARE_TITLE_AttacksPerProtocol   = MainActivity.getContext().getString(R.string.stats_attacks_protocol);
+    //static  final String COMPARE_TITLE_UsesPerProtocol      = MainActivity.getContext().getString(R.string.stats_uses_protocol);
+    static  final String COMPARE_TITLE_AttacksPerDate       = MainActivity.getContext().getString(R.string.stats_attacks_date);
+    static  final String COMPARE_TITLE_AttacksPerTime       = MainActivity.getContext().getString(R.string.stats_attacks_time);
+    static  final String COMPARE_TITLE_AttacksPerBSSID      = MainActivity.getContext().getString(R.string.stats_attacks_bssid);
+    static  final String COMPARE_TITLE_AttacksPerESSID      = MainActivity.getContext().getString(R.string.stats_attacks_essid);
+    static final String FILTER_MENU_PROTOCOL_SINGLE_CHOICE_TITLE = MainActivity.getContext().getString(R.string.stats_select_protocol);
+
+    static final String TABLE_HEADER_VALUE_TITLE_ATTACKS_COUNT = MainActivity.getContext().getString(R.string.stats_attacks_count);
+    static final String TABLE_HEADER_VALUE_TITLE_ATTACKS_PERCENTAGE = MainActivity.getContext().getString(R.string.stats_per_cent_all);
+
+
+    static final String OTHER_CHART_TITLE = MainActivity.getContext().getString(R.string.stats_other);
+
+    // MINIMAL 2
+    static int MAX_NUMBER_OF_CHART_OBJECTS = 6;
+
+    private boolean wasBelowTimePicker;
+
+    private LogFilter filter;
+
+    /*Maybe used in the future if the users doesn't need a filterbutton in every situation*/
+    private boolean showFilterButton;
+
+    private PieGraph pieGraph;
+    private LineGraph lineGraph;
+    private BarGraph barGraph;
+
+    private View rootView;
+    private View currentPlotView;
+
+    private Thread loader;
+    private ProgressBar spinner;
+
+    private ArrayList<PlotComparisonItem> currentData;
+
+    private HostageDBOpenHelper dbh;
+
+    private ListView legendListView;
+
+    private Toast noDataNotificationToast;
+
+
+    private String selectedCompareData = COMPARE_TITLE_AttacksPerProtocol;
+
+
+    /**The Charttype.
+     * PIE_CHART = 0
+     * BAR_CHART = 1
+     * LINE_CHART = 2
+     */
+    public enum ChartType {
+        PIE_CHART(0),
+        BAR_CHART(1),
+        LINE_CHART(2);
+
+        private int value;
+
+        private ChartType(int value) {
+            this.value = value;
+        }
+        static public ChartType create(int value){
+            if (value < 0 || value  >= ChartType.values().length) return ChartType.PIE_CHART;
+            return  ChartType.values()[value];
+        }
+
+        public String toString(){
+            if (this.equals(ChartType.create(0))){
+                return CHART_TYPE_TITLE_PIE;
+            }
+            if (this.equals(ChartType.create(1))){
+                return CHART_TYPE_TITLE_BAR;
+            }
+            return CHART_TYPE_TITLE_LINE;
+        }
+
+    }
+
+    /**Returns the FilterButton.
+    * @return ImageButton filterButton*/
+    private ImageButton getFilterButton(){
+        return (ImageButton) this.rootView.findViewById(R.id.FilterButton);
+    }
+
+    /**
+    * Returns the layout ID
+    * @Return int layoutID
+    * */
+    public int getLayoutID(){
+        return R.layout.fragment_statistics;
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                             Bundle savedInstanceState) {
+
+	    super.onCreateView(inflater, container, savedInstanceState);
+
+	    getActivity().setTitle(getResources().getString(R.string.drawer_statistics));
+
+        dbh = new HostageDBOpenHelper(this.getBaseContext());
+
+        // Get the message from the intent
+
+        if (this.filter == null){
+            Intent intent = this.getActivity().getIntent();
+            LogFilter filter = intent.getParcelableExtra(LogFilter.LOG_FILTER_INTENT_KEY);
+            if(filter == null){
+                this.clearFilter();
+            } else {
+                this.filter = filter;
+            }
+        }
+
+        this.rootView = inflater.inflate(this.getLayoutID(), container, false);
+
+        this.configureRootView(this.rootView);
+
+        return this.rootView;
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setHasOptionsMenu(true);
+        setRetainInstance(true);
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration newConfig){
+        super.onConfigurationChanged(newConfig);
+        LayoutInflater inflater = LayoutInflater.from(getActivity());
+
+        ViewGroup container = (ViewGroup) this.getView();
+        container.removeAllViewsInLayout();
+        this.rootView = inflater.inflate(this.getLayoutID(), container, false);
+        container.addView(this.rootView);
+
+        this.configureRootView(this.rootView);
+
+    }
+
+    /**Returns the base context.
+    * @return Context the base context
+    * */
+    private Context getBaseContext(){
+        return this.getActivity().getBaseContext();
+    }
+
+    /**Returns the application context.
+    * @return Context the application context*/
+    private Context getApplicationContext(){
+        return this.getActivity().getApplicationContext();
+    }
+
+    /**Configures the given rootview.
+    * Sets the Spinner, the list and all requiered buttons.
+    * It also actualises the current plot type.
+    * @param  rootView View
+    * */
+    public void configureRootView(View rootView){
+        LinearLayout plotLayout = (LinearLayout) rootView.findViewById(R.id.plot_layout);
+        plotLayout.removeAllViews();
+        plotLayout.setWillNotDraw(false);
+
+        ProgressBar spinner = (ProgressBar) rootView.findViewById(R.id.progressBar1);
+        if(spinner != null){
+            this.spinner = spinner;
+            this.spinner.setVisibility(View.GONE);
+        } else {
+            RelativeLayout parent = (RelativeLayout) this.spinner.getParent();
+            parent.removeView(this.spinner);
+            RelativeLayout newParent = (RelativeLayout) rootView.findViewById(R.id.plot_parent_layout);
+            if (newParent != null){
+                newParent.addView(this.spinner);
+            }
+        }
+
+        this.legendListView = (ListView) rootView.findViewById(R.id.legend_list_view);
+        this.legendListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+            @Override
+            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
+                StatisticsFragment.this.userTappedOnLegendItem(i);
+            }
+        });
+        rootView.setWillNotDraw(false);
+
+        ImageButton visualButton = (ImageButton) rootView.findViewById(R.id.plot_data_button);
+        visualButton.setOnClickListener(new View.OnClickListener() {
+            public void onClick(View v) {
+                StatisticsFragment.this.openBarSelectionMenuOnView(v);
+            }
+        });
+
+
+        ImageButton filterButton = this.getFilterButton();
+        filterButton.setOnClickListener(new View.OnClickListener() {
+            public void onClick(View v) {
+                StatisticsFragment.this.openFilterMenuOnView(v);
+            }
+        });
+
+        this.actualiseCurrentPlot();
+
+        if (this.currentPlotView instanceof BarGraph){
+            this.setTitle("" + this.getCurrentSelectedProtocol() + ": " +this.selectedCompareData);
+        } else {
+            this.setTitle(this.selectedCompareData);
+        }
+    }
+
+    /**Sets the title over the plot view.
+    * @param  title String
+    * */
+    public void setTitle(String title){
+        TextView titleView = (TextView) this.rootView.findViewById(R.id.title_text_view);
+        if (title != null && titleView != null){
+            titleView.setText(title);
+            titleView.invalidate();
+        }
+    }
+
+    /**Returns the title over the plot view.
+    * @return String title
+    * */
+    public String getTitle(){
+        TextView titleView = (TextView) this.rootView.findViewById(R.id.title_text_view);
+        if (titleView != null){
+            return "" + titleView.getText();
+        }
+        return "";
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+        this.actualiseCurrentPlot();
+        this.currentPlotView.invalidate();
+
+        if (this.currentPlotView instanceof BarGraph){
+            this.setTitle("" + this.getCurrentSelectedProtocol() + ": " +this.selectedCompareData);
+        } else {
+            this.setTitle(this.selectedCompareData);
+        }
+    }
+
+    /**Sets the current chart to the given type and acualises it.
+    * @param  type  {@link de.tudarmstadt.informatik.hostage.ui2.fragment.StatisticsFragment.ChartType ChartType}
+    * */
+    public void setChartType(ChartType type){
+        boolean shouldChange = true;
+        this.clearFilter();
+        if (this.currentPlotView != null){
+            if (type == ChartType.PIE_CHART){
+                shouldChange = ! (this.currentPlotView instanceof PieGraph);
+                // SET FILTER BUTTON HIDDEN
+                ImageButton filterButton = this.getFilterButton();
+                if (filterButton != null) filterButton.setVisibility(View.GONE);
+            } else {
+                if (this.pieGraph != null)
+                     this.pieGraph.setVisibility(View.GONE);
+                // SHOW FILTER BUTTON
+                ImageButton filterButton = this.getFilterButton();
+                if (filterButton != null) filterButton.setVisibility(View.VISIBLE);
+            }
+            if (type == ChartType.LINE_CHART){
+                shouldChange = ! (this.currentPlotView instanceof LineGraph);
+            } else {
+                if (this.lineGraph != null)
+                     this.lineGraph.setVisibility(View.GONE);
+            }
+            if (type == ChartType.BAR_CHART){
+                shouldChange = ! (this.currentPlotView instanceof BarGraph);
+
+            } else {
+                if (this.barGraph != null)
+                    this.barGraph.setVisibility(View.GONE);
+
+            }
+        }
+        if (shouldChange){
+            this.currentPlotView = this.getPlotViewForType(type);
+            this.currentPlotView.setVisibility(View.VISIBLE);
+
+        }
+        this.actualiseCurrentPlot();
+
+    }
+
+    /**Returns the plot view for a given type.
+    * @param type  {@link de.tudarmstadt.informatik.hostage.ui2.fragment.StatisticsFragment.ChartType ChartType}
+    * */
+    public View getPlotViewForType(ChartType type){
+        switch (type){
+            case PIE_CHART:
+                return this.getPieGraphView();
+            case LINE_CHART:
+                return this.getLineGraphView();
+            default:
+                return this.getBarGraphView();
+        }
+    }
+
+    /**Actualises the list view. Therefore it requiers the "currentData".*/
+    public void actualiseLegendList(){
+        StatisticListAdapter adapter = new StatisticListAdapter(this.getApplicationContext(), this.currentData);
+        if (this.currentPlotView instanceof LineGraph){
+            adapter.setValueFormatter(new StatisticListAdapter.ValueFormatter() {
+                @Override
+                public String convertValueForItemToString(PlotComparisonItem item) {
+                    return String.format("%.02f", item.getValue2()) + " %" + " " + "("+ (item.getValue1().intValue())  +")";
+                }
+            });
+        } else {
+
+            adapter.setValueFormatter(new StatisticListAdapter.ValueFormatter() {
+                @Override
+                public String convertValueForItemToString(PlotComparisonItem item)  {
+                    int v = (int) item.getValue2().intValue();
+                    return "" + v;
+                }
+            });
+
+        }
+        this.legendListView.setAdapter(adapter);
+
+        TextView tableHeaderTitleView = (TextView) this.rootView.findViewById(R.id.table_header_title_textview);
+        TextView tableHeaderValueView = (TextView) this.rootView.findViewById(R.id.table_header_value_textview);
+        if (this.currentPlotView instanceof LineGraph){
+            tableHeaderTitleView.setText(FILTER_MENU_TITLE_ESSID);
+            tableHeaderValueView.setText(TABLE_HEADER_VALUE_TITLE_ATTACKS_PERCENTAGE);
+        }
+        if (this.currentPlotView instanceof PieGraph){
+            tableHeaderTitleView.setText(FILTER_MENU_TITLE_PROTOCOL);
+            tableHeaderValueView.setText(TABLE_HEADER_VALUE_TITLE_ATTACKS_COUNT);
+        }
+        if (this.currentPlotView instanceof BarGraph){
+            tableHeaderValueView.setText(TABLE_HEADER_VALUE_TITLE_ATTACKS_COUNT);
+            if (this.selectedCompareData.equals(COMPARE_TITLE_AttacksPerBSSID)){
+                tableHeaderTitleView.setText(FILTER_MENU_TITLE_BSSID);
+            } else {
+                tableHeaderTitleView.setText(FILTER_MENU_TITLE_ESSID);
+            }
+        }
+        if (this.currentData == null || this.currentData.isEmpty()){
+            tableHeaderTitleView.setText("");
+            tableHeaderValueView.setText("");
+        }
+    }
+
+    /*
+    * MENU
+    * */
+    /**Opens the Bar Option Menu above the given anchor view.
+    * @param anchorView View*/
+     private void openBarSelectionMenuOnView(View anchorView){
+        SimplePopupTable visualiseMenu = new SimplePopupTable(this.getActivity(), new AbstractPopup.OnPopupItemClickListener() {
+            public void onItemClick(Object ob) {
+                if (ob instanceof AbstractPopupItem){
+                    AbstractPopupItem item = (AbstractPopupItem) ob;
+                    StatisticsFragment.this.userSelectMenuItem(item);
+                }
+            }
+        });
+        visualiseMenu.setTitle(MENU_POPUP_TITLE);
+        int id = 0;
+        for(String title : StatisticsFragment.this.getMenuTitles()){
+            SimplePopupItem item = new SimplePopupItem(this.getActivity());
+            item.setTitle(title);
+            item.setItemId(id);
+            item.setSelected(false);
+            visualiseMenu.addItem(item);
+            id++;
+        }
+        visualiseMenu.showOnView(anchorView);
+    }
+
+    /**Will be called when the users selected an menu item (visualise menu / plot menu).
+    * If the user selected "Protocols" this method sets the current plot type to piegraph.
+    * Otherwise it will open a new dialog to select the comparison type.
+    * */
+    private void userSelectMenuItem(AbstractPopupItem item){
+        // OPEN A DIALOG TO SPECIFY THE VISUALISE DATA
+        if (item.getTitle().equals(MENU_TITLE_PROTOCOLS)){
+            ChartType chartType = ChartType.PIE_CHART;
+            this.selectedCompareData = COMPARE_TITLE_AttacksPerProtocol;
+            this.setChartType(chartType);
+            this.setTitle(COMPARE_TITLE_AttacksPerProtocol);
+        }
+        if (item.getTitle().equals(MENU_TITLE_NETWORK)){
+            this.openNetworkDataDialog();
+        }
+        if (item.getTitle().equals(MENU_TITLE_ATTACKS)){
+            this.openAttackDataDialog();
+        }
+    }
+
+    /**Returns the menu titles (visualise menu / plot menu)*/
+    private ArrayList<String> getMenuTitles(){
+        ArrayList<String> titles = new ArrayList<String>();
+        titles.add(MENU_TITLE_PROTOCOLS);
+        titles.add(MENU_TITLE_NETWORK);
+        titles.add(MENU_TITLE_ATTACKS);
+        return titles;
+    }
+
+    /*
+    * PLOT DATA DIALOGS
+    * */
+//     private void openProtocolDataDialog(){
+//        ArrayList<String> titles = this.getDialogProtocolDataTitle();
+//        ChecklistDialog newFragment = new ChecklistDialog(DIALOG_PROTOCOLS_TITLE, titles, this.selectedData(titles), false , this);
+//        newFragment.show(this.getActivity().getFragmentManager(), DIALOG_PROTOCOLS_TITLE);
+//    }
+    /**Opens the network comparison dialog*/
+    private void openNetworkDataDialog(){
+        ArrayList<String> titles = this.getDialogNetworkDataTitle();
+        ChecklistDialog newFragment = new ChecklistDialog(DIALOG_NETWORK_TITLE, titles, this.selectedData(titles), false , this);
+        newFragment.show(this.getActivity().getFragmentManager(), DIALOG_NETWORK_TITLE);
+    }
+    /**Opens the attack comparison dialog*/
+    private void openAttackDataDialog(){
+        ArrayList<String> titles = this.getDialogAttackDataTitle();
+        ChecklistDialog newFragment = new ChecklistDialog(DIALOG_ATTACK_TITLE, titles, this.selectedData(titles), false , this);
+        newFragment.show(this.getActivity().getFragmentManager(), DIALOG_ATTACK_TITLE);
+    }
+
+    /*
+    *
+    * DIALOG ACTION METHODS
+    *
+    * */
+    /**
+     * Will be called if the user selects the positiv button on an checklist dialog.
+     * @param dialog  {@link ChecklistDialog ChecklistDialog}
+     * */
+     public void onDialogPositiveClick(ChecklistDialog dialog) {
+        String title = dialog.getTitle();
+        ArrayList<String> titles =dialog.getSelectedItemTitles();
+
+        if (title.equals(FILTER_MENU_TITLE_PROTOCOLS)){
+            //titles = titles.size() == 0 ? this.protocolTitles() : titles;
+            this.filter.setProtocols(titles);
+            this.actualiseCurrentPlot();
+            return;
+        }
+        if (title.equals(FILTER_MENU_PROTOCOL_SINGLE_CHOICE_TITLE)){
+            if (titles.size() == 0){
+                titles = new ArrayList<String>();
+                titles.add(this.protocolTitles().get(0));
+            }
+            this.filter.setProtocols(titles);
+
+            this.actualiseCurrentPlot();
+            String fragTitle = "" + this.getCurrentSelectedProtocol() + ": " + this.selectedCompareData;
+            this.setTitle(fragTitle);
+
+            return;
+        }
+        if (title.equals(FILTER_MENU_TITLE_ESSID)){
+            this.filter.setESSIDs(titles);
+            this.actualiseCurrentPlot();
+
+            return;
+        }
+        if (title.equals(FILTER_MENU_TITLE_BSSID)){
+            this.filter.setBSSIDs(titles);
+            this.actualiseCurrentPlot();
+
+            return;
+        }
+
+        if (titles.size() != 0){
+            String data = titles.get(0);
+            this.setTitle(data);
+
+            this.actualiseFilterButton();
+
+            if (data.equals(COMPARE_TITLE_AttacksPerTime) || data.equals(COMPARE_TITLE_AttacksPerDate)){
+                ChartType chartType = ChartType.LINE_CHART;
+                this.selectedCompareData = data;
+                this.setChartType(chartType);
+                return;
+            }
+            if (data.equals(COMPARE_TITLE_AttacksPerBSSID) || data.equals(COMPARE_TITLE_AttacksPerESSID)){
+                ChartType chartType = ChartType.BAR_CHART;
+                this.selectedCompareData = data;
+                this.setChartType(chartType);
+
+                String fragTitle = "" + this.getCurrentSelectedProtocol() + ": " + this.selectedCompareData;
+                this.setTitle(fragTitle);
+                return;
+            }
+        }
+
+    }
+
+    /**
+     * Will be called if the user selects the negativ button on an checklist dialog.
+     * @param dialog  {@link ChecklistDialog ChecklistDialog}
+     * */
+    public void onDialogNegativeClick(ChecklistDialog dialog) {
+
+    }
+    /*
+    *
+    * DIALOG DATA
+    *
+    * */
+
+
+//     private ArrayList<String> getDialogProtocolDataTitle(){
+//        ArrayList<String> data = new ArrayList<String>();
+//        data.add(COMPARE_TITLE_AttacksPerProtocol);
+//        data.add(COMPARE_TITLE_UsesPerProtocol);
+//        return data;
+//    }
+    /**
+     *  Returns the Attacks comparison titles.
+     * @return  ArrayList<String> the titles
+     */
+    private ArrayList<String> getDialogAttackDataTitle(){
+        ArrayList<String> data = new ArrayList<String>();
+        data.add(COMPARE_TITLE_AttacksPerDate);
+        data.add(COMPARE_TITLE_AttacksPerTime);
+        return data;
+    }
+    /**
+     *  Returns the network comparison titles.
+     * @return  ArrayList<String> the titles
+     */
+    private ArrayList<String> getDialogNetworkDataTitle(){
+        ArrayList<String> data = new ArrayList<String>();
+        data.add(COMPARE_TITLE_AttacksPerESSID);
+        data.add(COMPARE_TITLE_AttacksPerBSSID);
+        return data;
+    }
+    /**
+     * DEFAULT
+     *  Returns an boolean array with a default selection. Just the first object is true.
+     * @return  boolean[] selected array
+     */
+    private boolean[] selectedData(ArrayList<String> data){
+        boolean[] selected = new boolean[data.size()];
+         // SET DEFAULT
+        selected[0] = true;
+        return selected;
+    }
+
+    /*
+    *
+    *  FILTER BUTTON
+    *
+    * */
+
+    /**Paints the filter button if the current filter object is set.*/
+    private void actualiseFilterButton(){
+        if ((this.filter.isSet() && (!(this.currentPlotView instanceof BarGraph))|| (this.filter.hasATimestamp() || this.filter.hasBSSIDs() || this.filter.hasESSIDs()))){
+            ImageButton filterButton = this.getFilterButton();
+            if (filterButton != null){
+                filterButton.setImageResource(R.drawable.ic_filter_pressed);
+                filterButton.invalidate();
+            }
+        } else {
+            ImageButton filterButton = this.getFilterButton();
+            if (filterButton != null){
+                filterButton.setImageResource(R.drawable.ic_filter);
+                filterButton.invalidate();
+            }
+        }
+    }
+
+    /**
+     * Opens the filter menu above an given anchor view.
+     * @param  anchor View
+     */
+     private void openFilterMenuOnView(View anchor){
+        SimplePopupTable filterMenu = new SimplePopupTable(this.getActivity(), new AbstractPopup.OnPopupItemClickListener() {
+            public void onItemClick(Object ob) {
+                if (ob instanceof  AbstractPopupItem){
+                    AbstractPopupItem item = (AbstractPopupItem) ob;
+                    StatisticsFragment.this.onFilterMenuItemSelected(item);
+                }
+            }
+        });
+
+        filterMenu.setTitle(FILTER_MENU_POPUP_TITLE);
+        for(String title : StatisticsFragment.this.filterMenuTitles()){
+            AbstractPopupItem item = null;
+            if (title.equals(FILTER_MENU_TITLE_TIMESTAMP_BELOW)) continue;
+            if (title.equals(FILTER_MENU_TITLE_TIMESTAMP_ABOVE)){
+                item = new SplitPopupItem(this.getActivity());
+                item.setValue(SplitPopupItem.RIGHT_TITLE, FILTER_MENU_TITLE_TIMESTAMP_BELOW);
+                item.setValue(SplitPopupItem.LEFT_TITLE, FILTER_MENU_TITLE_TIMESTAMP_ABOVE);
+                if (this.filter.hasBelowTimestamp()){
+                    item.setValue(SplitPopupItem.RIGHT_SUBTITLE, this.getDateAsString(this.filter.belowTimestamp));
+                }
+                if (this.filter.hasAboveTimestamp()){
+                    item.setValue(SplitPopupItem.LEFT_SUBTITLE, this.getDateAsString(this.filter.aboveTimestamp));
+                }
+            } else {
+                item = new SimplePopupItem(this.getActivity());
+                item.setTitle(title);
+                ((SimplePopupItem)item).setSelected(this.isFilterSetForTitle(title));
+            }
+
+            filterMenu.addItem(item);
+        }
+        filterMenu.showOnView(anchor);
+    }
+
+    /**
+     * Will be called if the user selected an filter item.
+     * @param  item  {@link AbstractPopupItem AbstractPopupItem}
+     */
+    private void onFilterMenuItemSelected(AbstractPopupItem item){
+        if (item instanceof SplitPopupItem){
+            SplitPopupItem sItem = (SplitPopupItem) item;
+            this.wasBelowTimePicker = sItem.wasRightTouch;
+            if (this.wasBelowTimePicker){
+                this.openTimestampToFilterDialog();
+            } else {
+                this.openTimestampFromFilterDialog();
+            }
+            return;
+        }
+        String title = item.getTitle();
+        if (title.equals(FILTER_MENU_TITLE_ESSID)){
+            this.openESSIDFilterDialog();
+        }
+        if (title.equals(FILTER_MENU_TITLE_BSSID)){
+            this.openBSSIDFilterDialog();
+        }
+        if (title.equals(FILTER_MENU_TITLE_PROTOCOL)){
+            this.openFilterDialogSelectProtocol();
+        }
+        if (title.equals(FILTER_MENU_TITLE_PROTOCOLS)){
+            this.openProtocolsFilterDialog();
+        }
+        if (title.equals(FILTER_MENU_TITLE_REMOVE)){
+            this.clearFilter();
+            this.actualiseCurrentPlot();
+        }
+    }
+
+    /**
+     * Return the menu titles of the filter menu.
+     * @return ArrayList<String> filter menu title
+     * */
+    private ArrayList<String> filterMenuTitles(){
+        ArrayList<String> titles = new ArrayList<String>();
+        if (this.currentPlotView instanceof LineGraph){
+            titles.add(FILTER_MENU_TITLE_ESSID);
+            titles.add(FILTER_MENU_TITLE_PROTOCOLS);
+            titles.add(FILTER_MENU_TITLE_TIMESTAMP_ABOVE);
+            if (this.filter.hasESSIDs() || this.filter.hasATimestamp() || (this.filter.getProtocols() != null  && this.filter.hasProtocols() && this.filter.getProtocols().size() != this.protocolTitles().size())){
+                titles.add(FILTER_MENU_TITLE_REMOVE);
+            }
+        } else {
+            titles.add(FILTER_MENU_TITLE_PROTOCOL);
+            String protocol = this.getCurrentSelectedProtocol();
+            if (protocol.length() > 0){
+                if (this.selectedCompareData.equals(COMPARE_TITLE_AttacksPerBSSID)){
+                    titles.add(FILTER_MENU_TITLE_BSSID);
+                } else {
+                    // DEFAULT
+                    titles.add(FILTER_MENU_TITLE_ESSID);
+                }
+            }
+            titles.add(FILTER_MENU_TITLE_TIMESTAMP_ABOVE);
+            if (this.filter.hasATimestamp() || this.filter.hasESSIDs() || this.filter.hasBSSIDs()
+                    || (this.currentPlotView instanceof LineGraph && this.filter.hasProtocols())){
+                titles.add(FILTER_MENU_TITLE_REMOVE);
+            }
+        }
+        return titles;
+    }
+
+    /**
+     * Opens a multiple protocol checklist dialog
+     */
+    private void openProtocolsFilterDialog(){
+        ChecklistDialog newFragment = new ChecklistDialog(FILTER_MENU_TITLE_PROTOCOLS,
+                                                    this.protocolTitles(),
+                                                    this.selectedProtocols(),
+                                                    true ,
+                                                    this);
+        newFragment.show(this.getActivity().getFragmentManager(), FILTER_MENU_TITLE_PROTOCOLS);
+    }
+
+    /**
+     * Opens a single protocol checklist dialog
+     */
+    private void openFilterDialogSelectProtocol(){
+        ArrayList<String> titles = this.protocolTitles();
+        boolean[] selected = new boolean[titles.size()];
+        int i = 0;
+        for (String title : titles){
+            selected[i] = title.equals(this.getCurrentSelectedProtocol());
+            i++;
+        }
+        ChecklistDialog newFragment = new ChecklistDialog(FILTER_MENU_PROTOCOL_SINGLE_CHOICE_TITLE, titles, selected, false , this);
+        newFragment.show(this.getActivity().getFragmentManager(), FILTER_MENU_PROTOCOL_SINGLE_CHOICE_TITLE);
+    }
+
+    /**
+     * Opens a multiple essid checklist dialog
+     */
+    private void openESSIDFilterDialog(){
+        ChecklistDialog newFragment = new ChecklistDialog(FILTER_MENU_TITLE_ESSID, this.essids(), this.selectedESSIDs(), true , this);
+        newFragment.show(this.getActivity().getFragmentManager(), FILTER_MENU_TITLE_ESSID);
+    }
+
+    /**Opens a multiple bssid checlist dialog.*/
+    private void openBSSIDFilterDialog(){
+        ChecklistDialog newFragment = new ChecklistDialog(FILTER_MENU_TITLE_BSSID, this.bssids(), this.selectedBSSIDs(), true , this);
+        newFragment.show(this.getActivity().getFragmentManager(), FILTER_MENU_TITLE_BSSID);
+    }
+
+    /** Opens a minimal timestamp dialog.**/
+    private void openTimestampFromFilterDialog(){
+        this.wasBelowTimePicker = false;
+        DateTimeDialogFragment newFragment = new DateTimeDialogFragment(this.getActivity());
+        newFragment.setDateChangeListener(this);
+        newFragment.show(this.getActivity().getFragmentManager(), FILTER_MENU_TITLE_TIMESTAMP_ABOVE);
+
+        if (this.filter.aboveTimestamp != Long.MIN_VALUE)newFragment.setDate(this.filter.aboveTimestamp);
+    }
+
+    /** Opens the maximal timestamp dialog.*/
+    private void openTimestampToFilterDialog(){
+        this.wasBelowTimePicker = true;
+        DateTimeDialogFragment newFragment = new DateTimeDialogFragment(this.getActivity());
+        newFragment.setDateChangeListener(this);
+        newFragment.show(this.getActivity().getFragmentManager(), FILTER_MENU_TITLE_TIMESTAMP_BELOW);
+        if (this.filter.belowTimestamp != Long.MAX_VALUE) newFragment.setDate(this.filter.belowTimestamp);
+    }
+
+    /** Returns all essids
+     * If the current plot is a bar graph, it just return all possible essids for the selected protocol
+     * @return ArrayList<String> essids
+     * */
+    public ArrayList<String> essids(){
+        ArrayList<String> records;
+        if (this.currentPlotView instanceof BarGraph){
+            records = dbh.getUniqueESSIDRecordsForProtocol(this.getCurrentSelectedProtocol());
+        } else {
+            records = dbh.getUniqueESSIDRecords();
+        }
+        return records;
+    }
+    /** Returns a boolean array. The position in the array will be true, if the essid is selected in the filter.
+     * @return boolean[] selected essids*/
+    public boolean[] selectedESSIDs(){
+        ArrayList<String> essids = this.essids();
+        boolean[] selected = new boolean[essids.size()];
+
+        int i = 0;
+        for(String essid : essids){
+            selected[i] =(this.filter.getESSIDs().contains(essid));
+            i++;
+        }
+        return selected;
+    }
+
+    /** Returns all bssids
+     * If the current plot is a bar graph, it just return all possible bssids for the selected protocol
+     * @return ArrayList<String> bssids
+     * */
+    public ArrayList<String> bssids(){
+        ArrayList<String> records ;
+        if (this.currentPlotView instanceof BarGraph){
+            records = dbh.getUniqueBSSIDRecordsForProtocol(this.getCurrentSelectedProtocol());
+        } else {
+            records = dbh.getUniqueBSSIDRecords();
+        }
+        return records;
+    }
+    /** Returns a boolean array. The position in the array will be true, if the bssid is selected in the filter.
+     * @return boolean[] selected bssids*/
+    public boolean[] selectedBSSIDs(){
+        ArrayList<String> bssids = this.bssids();
+
+        boolean[] selected = new boolean[bssids.size()];
+
+        int i = 0;
+        for(String bssid : bssids){
+            selected[i] =(this.filter.getBSSIDs().contains(bssid));
+            i++;
+        }
+        return selected;
+    }
+
+    /**Will be called if the user selects an date on the timestamp dialog*/
+    public void onDateTimePickerPositiveClick(DateTimeDialogFragment dialog) {
+        if(this.wasBelowTimePicker){
+            this.filter.setBelowTimestamp(dialog.getDate());
+        } else {
+            this.filter.setAboveTimestamp(dialog.getDate());
+        }
+        this.actualiseCurrentPlot();
+    }
+
+    /**Will be called if the user cancels an date selection on the timestamp dialog*/
+    public void onDateTimePickerNegativeClick(DateTimeDialogFragment dialog) {
+        if(this.wasBelowTimePicker){
+            this.filter.setBelowTimestamp(Long.MAX_VALUE);
+        } else {
+            this.filter.setAboveTimestamp(Long.MIN_VALUE);
+        }
+        this.actualiseCurrentPlot();
+    }
+
+
+    /*
+    *
+    *  PLOT TYPES
+    *
+    * **/
+    /**Returns the current pie graph.
+     * @return PieGraph current piegraph*/
+     public PieGraph getPieGraphView(){
+        if (this.pieGraph == null) {
+            this.pieGraph = new PieGraph(this.getApplicationContext());
+            LinearLayout plotLayout = (LinearLayout) this.rootView.findViewById(R.id.plot_layout);
+            plotLayout.addView(this.pieGraph);
+            this.pieGraph.setOnSliceClickedListener(new PieGraph.OnSliceClickedListener() {
+                @Override
+                public void onClick(int index) {
+                    StatisticsFragment.this.onSliceClick(index);
+                }
+            });
+        }
+         return this.pieGraph;
+    }
+
+    /**
+     * Returns the current  {@link com.echo.holographlibrary.LineGraph Linegraph} .
+     * @return LineGraph current line graph
+     */
+    public LineGraph getLineGraphView(){
+        if (this.lineGraph == null) {
+            this.lineGraph = new LineGraph(this.getActivity());
+            LinearLayout plotLayout = (LinearLayout) this.rootView.findViewById(R.id.plot_layout);
+            plotLayout.addView(this.lineGraph);
+            this.lineGraph.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT));
+        }
+        return this.lineGraph;
+    }
+
+    /**
+     * Returns the current  {@link com.echo.holographlibrary.BarGraph BarGraph} .
+     * @return BarGraph the current bar graph
+     */
+    public BarGraph getBarGraphView(){
+        if (this.barGraph == null) {
+            this.barGraph = new BarGraph(this.getActivity());
+            LinearLayout plotLayout = (LinearLayout) this.rootView.findViewById(R.id.plot_layout);
+            this.barGraph.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT ));
+            plotLayout.addView(this.barGraph);
+            this.barGraph.setShowBarText(false);
+            this.barGraph.setPopupImageID(R.drawable.popup_black);
+            this.barGraph.setOnBarClickedListener(new BarGraph.OnBarClickedListener() {
+                @Override
+                public void onClick(int i) {
+                    StatisticsFragment.this.onBarClick(i);
+                }
+            });
+        }
+        return this.barGraph;
+    }
+
+    /*
+    *  FEED PLOTS WITH DATA
+    * */
+
+    /**
+     * Sets the data for the given PieGraph
+     * @param piegraph  {@link com.echo.holographlibrary.PieGraph PieGraph}
+     */
+     public void setPieGraphData(PieGraph piegraph){
+        this.currentData = this.getPieData();
+        if (this.currentData == null){
+            this.currentData = new ArrayList<PlotComparisonItem>();
+        }
+
+        piegraph.removeSlices();
+
+        for (PlotComparisonItem item : this.currentData){
+            PieSlice slice = new PieSlice();
+            slice.setColor(item.getColor());
+            Double value2 = (Double) item.getValue2();
+            float v = value2.floatValue();
+            slice.setValue(v);
+            slice.setTitle(item.getTitle());
+            piegraph.addSlice(slice);
+        }
+        //piegraph.invalidate();
+    }
+
+
+    /**
+     * Sets the data for the given LineGraph
+     * @param linegraph {@link LineGraph Linegraph}
+     */
+    public void setLineGraphData(LineGraph linegraph){
+        this.currentData = this.getLineData();
+        if (this.currentData == null){
+            this.currentData = new ArrayList<PlotComparisonItem>();
+        }
+
+        linegraph.removeAllLines();
+        double rangeMax_Y = 0;
+        double rangeMin_Y = 0;
+
+        double rangeMax_X = 0;
+        double rangeMin_X = 0;
+
+        int count = 0;
+        for (PlotComparisonItem lineItem : this.currentData){
+            ArrayList<PlotComparisonItem> data = lineItem.getChildItems();
+            //int index = 0;
+            Line l = new Line();
+            int lineColor = lineItem.getColor();
+            l.setColor(lineColor);
+
+            for (PlotComparisonItem pointItem : data){
+                LinePoint p = new LinePoint();
+                p.setX(pointItem.getValue1());
+                Double value2 = pointItem.getValue2();
+                p.setY(value2);
+                p.setColor(lineColor);
+                l.addPoint(p);
+                rangeMax_Y = Math.max(pointItem.getValue2(), rangeMax_Y);
+                rangeMax_X = Math.max(pointItem.getValue1(), rangeMax_X);
+
+                if (count != 0){
+                    rangeMin_Y = Math.min(pointItem.getValue2(), rangeMin_Y);
+                    rangeMin_X = Math.min(pointItem.getValue1(), rangeMin_X);
+                } else {
+                    rangeMin_Y = pointItem.getValue2();
+                    rangeMin_X = pointItem.getValue1();
+                }
+                //index++;
+                count++;
+            }
+            linegraph.addLine(l);
+        }
+        // add a bit more space
+        rangeMax_Y++;
+        rangeMin_Y--;
+
+        boolean shouldUseDate = this.selectedCompareData.equals(COMPARE_TITLE_AttacksPerDate);
+        if (shouldUseDate){
+            linegraph.resetXLimits();
+
+            if (this.filter.hasBelowTimestamp()){
+                rangeMax_X = Math.max(this.filter.belowTimestamp, rangeMax_X);
+            }
+            if (this.filter.hasAboveTimestamp()){
+                rangeMin_X = Math.min(this.filter.aboveTimestamp, rangeMin_X);
+            }
+
+            if (rangeMax_X == rangeMin_X){
+                double aDay = 60*60*24*1000;
+                rangeMax_X+= aDay;
+                rangeMin_X-= aDay;
+            }
+
+            double stepRange = (rangeMax_X - rangeMin_X)/(60*60*24*1000);
+            linegraph.setxAxisStep(Math.max(1, (float) Math.min(stepRange, 4)));
+
+            linegraph.setRangeX(rangeMin_X  , rangeMax_X);
+
+            linegraph.setConverter(new LineGraph.AxisDataConverter() {
+                @Override
+                public String convertDataForX_Position(double x) {
+                    return StatisticsFragment.this.getDateAsDayString((long)x);
+                }
+                @Override
+                public  String convertDataForY_Position(double y){
+                    return "" + (long)y;
+                }
+            });
+        } else {
+            linegraph.setxAxisStep(12.f);
+            linegraph.setRangeX(0, 24);
+            linegraph.setConverter(null);
+        }
+
+        int maxY = (int)(rangeMax_Y - rangeMin_Y);
+        linegraph.setYAxisStep(Math.min(maxY, 5));
+        int yStep = (int)linegraph.getyAxisStep();
+        if ((maxY % yStep) != 0) {
+            maxY = maxY + (yStep - (maxY % yStep));
+        }
+        rangeMax_Y = rangeMin_Y + maxY;
+        linegraph.setRangeY(rangeMin_Y, rangeMax_Y);
+        linegraph.setLineToFill(0);
+    }
+
+    /**
+    * Set the graph data to the given graph
+    * @param bargraph {@link BarGraph BarGraph}
+    * */
+    public void setBarGraphData(BarGraph bargraph){
+        this.currentData = this.getBarData();
+        if (this.currentData == null){
+            this.currentData = new ArrayList<PlotComparisonItem>();
+        }
+
+        ArrayList<Bar> bars = new ArrayList<Bar>();
+
+        for (PlotComparisonItem item : this.currentData){
+            Bar d = new Bar();
+            d.setColor(item.getColor());
+            Long value2 =  item.getValue2().longValue();
+            d.setName("");
+            d.setValue(value2.floatValue());
+            bars.add(d);
+        }
+
+        barGraph.setBars(bars);
+    }
+
+    /*
+    *
+    *  FETCH & ACTUALISE RECORD DATA
+    *
+    * */
+    /**
+     * Returns the DataBaseHandler result for the current filter.
+     * @return records {@link java.util.ArrayList}, {@link Record Record}
+     */
+     public ArrayList<Record> getFetchedRecords(){
+        if (this.filter == null) this.clearFilter();
+        return this.dbh.getRecordsForFilter(this.filter);
+    }
+
+    /**Actualises the current plot in a background thread.*/
+     public void actualiseCurrentPlot(){
+         this.spinner.setVisibility(View.VISIBLE);
+
+         this.actualiseFilterButton();
+
+         LinearLayout plotLayout = (LinearLayout) this.rootView.findViewById(R.id.plot_layout);
+
+         if (this.barGraph != null)
+            this.barGraph.setVisibility(View.GONE);
+         if (this.lineGraph != null)
+            this.lineGraph.setVisibility(View.GONE);
+         if (this.pieGraph != null)
+            this.pieGraph.setVisibility(View.GONE);
+
+        View plot = this.currentPlotView;
+         if (plot == null){
+             this.currentPlotView = this.getPieGraphView();
+             plot = this.currentPlotView;
+         }
+         if (plot.getParent() != null && !plot.getParent().equals(plotLayout)){
+             LinearLayout linLayout = (LinearLayout)plot.getParent();
+             linLayout.removeView(plot);
+             plot.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.MATCH_PARENT ));
+             plotLayout.addView(plot);
+         }
+
+         this.currentPlotView = plot;
+
+         final LinearLayout thePlotlayout = plotLayout;
+
+         if (this.loader != null && this.loader.isAlive()) this.loader.interrupt();
+
+         this.loader = null;
+
+         this.loader = new Thread(new Runnable() {
+             @Override
+             public void run() {
+                 this.loadDataInBackground();
+                 this.actualiseUI();
+             }
+
+             private void loadDataInBackground(){
+                 View plot = StatisticsFragment.this.currentPlotView;
+                 if (plot instanceof PieGraph){
+                     PieGraph pie = (PieGraph) plot;
+                     StatisticsFragment.this.setPieGraphData(pie);
+                 }
+                 if (plot instanceof BarGraph){
+                     BarGraph bar = (BarGraph) plot;
+                     StatisticsFragment.this.setBarGraphData(bar);
+                 }
+                 if (plot instanceof LineGraph){
+                     LineGraph line = (LineGraph)plot;
+                     StatisticsFragment.this.setLineGraphData(line);
+                 }
+             }
+
+             private void actualiseUI(){
+
+                 Activity actv = StatisticsFragment.this.getActivity();
+
+                 if (actv != null){
+                     actv.runOnUiThread(new Runnable() {
+                         @Override
+                         public void run() {
+                             // SET VISIBILITY
+                             View plot = StatisticsFragment.this.currentPlotView;
+
+                             if (plot instanceof PieGraph){
+                                 // HIDE FILTER BUTTON
+                                 ImageButton filterButton = StatisticsFragment.this.getFilterButton();
+                                 if (filterButton != null) filterButton.setVisibility(View.GONE);
+                             } else {
+                                 if (StatisticsFragment.this.pieGraph != null){
+                                     StatisticsFragment.this.pieGraph.setVisibility(View.GONE);
+                                     if (StatisticsFragment.this.pieGraph.getParent() != null){
+                                         thePlotlayout.removeView(StatisticsFragment.this.pieGraph);
+                                     }
+                                 }
+                                 // SHOW FILTER BUTTON
+                                 ImageButton filterButton = StatisticsFragment.this.getFilterButton();
+                                 if (filterButton != null) filterButton.setVisibility(View.VISIBLE);
+                             }
+                             if (! (plot instanceof BarGraph)){
+                                 if (StatisticsFragment.this.barGraph != null){
+                                     StatisticsFragment.this.barGraph.setVisibility(View.GONE);
+                                     if (StatisticsFragment.this.barGraph.getParent() != null){
+                                         thePlotlayout.removeView(StatisticsFragment.this.barGraph);
+                                     }
+                                 }
+                             }
+                             if (!(plot instanceof LineGraph)){
+                                 if (StatisticsFragment.this.lineGraph != null){
+                                     StatisticsFragment.this.lineGraph.setVisibility(View.GONE);
+                                     if (StatisticsFragment.this.lineGraph.getParent() != null){
+                                         thePlotlayout.removeView(StatisticsFragment.this.lineGraph);
+                                     }
+                                 }
+                             }
+
+                             plot.setVisibility(View.VISIBLE);
+
+                             if (plot.getParent() == null){
+                                 thePlotlayout.addView(plot);
+                             }
+                             StatisticsFragment.this.actualiseLegendList();
+                             StatisticsFragment.this.currentPlotView.bringToFront();
+                             StatisticsFragment.this.currentPlotView.invalidate();
+
+                             StatisticsFragment.this.spinner.setVisibility(View.GONE);
+
+                             StatisticsFragment.this.showEmptyDataNotification();
+                         }
+                     });
+                 }
+             }
+         });
+
+        this.loader.start();
+     }
+
+    /**
+     * Shows a small toast if the data to show is empty (no records).
+     */
+    private void showEmptyDataNotification(){
+        if (this.noDataNotificationToast == null){
+            this.noDataNotificationToast =  Toast.makeText(getApplicationContext(), R.string.no_data_notification, Toast.LENGTH_SHORT);
+        }
+        if (this.getFilterButton().getVisibility() == View.VISIBLE){
+            this.noDataNotificationToast.setText(R.string.no_data_notification);
+        } else {
+            this.noDataNotificationToast.setText(R.string.no_data_notification_no_filter);
+        }
+        if (this.currentData == null || this.currentData.isEmpty()){
+            this.noDataNotificationToast.show();
+        }
+    }
+
+
+    /** Calculates and returns the data for the piegraph
+     * @return ArrayList<PlotComparisonItem> data */
+    public ArrayList<PlotComparisonItem> getPieData(){
+        // DEFAULT
+        return this.attacksPerProtocols();
+    }
+    /** Calculates and returns the data for the bargraph.
+     * @return ArrayList<PlotComparisonItem> data */
+    public ArrayList<PlotComparisonItem> getBarData(){
+        String protocol = this.getCurrentSelectedProtocol();
+
+        if (protocol.length() > 0){
+            if (this.selectedCompareData.equals(COMPARE_TITLE_AttacksPerESSID)){
+                return this.attacksPerESSID(protocol);
+            }
+            // DEFAULT
+            return this.attacksPerBSSID(protocol);
+        }
+        // Nothing available
+        return new ArrayList<PlotComparisonItem>();
+    }
+    /** Calculates and returns the data for the linegraph
+     * @return ArrayList<PlotComparisonItem> data */
+    public ArrayList<PlotComparisonItem> getLineData(){
+        return this.attacksPerTime();
+    }
+
+    /*
+    *  DATA SOURCE
+    * */
+
+    /*PROTOCOLS OVERVIEW*/
+
+    /**
+     * Returns the attacks per protocols comparison result.
+     * The returned data is resized to the specified limit.
+     * @return ArrayList<PlotComparisonItem>
+     */
+     public synchronized ArrayList<PlotComparisonItem> attacksPerProtocols(){
+        ArrayList<PlotComparisonItem> plotItems = new ArrayList<PlotComparisonItem>();
+         int index = 0;
+        for (String title : this.getSelectedProtocolTitles()){
+            int attacksCount = this.dbh.getAttackPerProtocolCount(title);
+            if (attacksCount == 0) continue;
+            PlotComparisonItem item = new PlotComparisonItem(title,this.getColor(index), 0., (double) attacksCount);
+            plotItems.add(item);
+            index++;
+        }
+         Collections.sort(plotItems, new Comparator<PlotComparisonItem>() {
+             @Override
+             public int compare(PlotComparisonItem s1, PlotComparisonItem s2) {
+                 return s2.getValue2().compareTo(s1.getValue2());
+             }
+         });
+         return this.resizeData(plotItems);
+    }
+
+
+    /*
+    *  LINE PLOT DATA
+    */
+
+    /**
+     * Returns the line graph data responding to the selectedCompareData key.
+     * The returned data is resized to the specified limit.
+     * @return plotItems {@link PlotComparisonItem PlotComparisonItems}
+     */
+    public ArrayList<PlotComparisonItem> attacksPerTime(){
+        HashMap<String,HashMap<Long, ArrayList<Record> > > lineMap = new HashMap<String, HashMap<Long, ArrayList<Record>>>();
+
+        boolean shouldUseDate = this.selectedCompareData.equals(COMPARE_TITLE_AttacksPerDate);
+
+        ArrayList<Record> records = this.getFetchedRecords();
+        for (Record record : records){
+            long timestamp = record.getTimestamp();
+            long time = 0;
+            if (shouldUseDate){
+                time = this.getDateFromMilliseconds(timestamp);
+            } else {
+                time = this.getDayHourFromDate(timestamp);
+            }
+
+            // GET CORRECT MAP
+            HashMap<Long, ArrayList<Record> > recordMap;
+            String groupKey = record.getSsid();
+            if (lineMap.containsKey(groupKey)){
+                recordMap = lineMap.get(record.getSsid());
+            } else {
+                recordMap = new HashMap<Long, ArrayList<Record> >();
+                lineMap.put(groupKey, recordMap);
+            }
+
+            // GET LIST OF RECORDS
+            ArrayList<Record> list;
+            if (recordMap.containsKey(time)){
+                list = recordMap.get(time);
+            } else {
+                list = new ArrayList<Record>();
+                recordMap.put(time, list);
+            }
+            list.add(record);
+        }
+
+        ArrayList<PlotComparisonItem> plotItems = new ArrayList<PlotComparisonItem>();
+
+        int index = 0;
+        for (String groupKey : lineMap.keySet()){
+            HashMap<Long, ArrayList<Record> > recordMap = lineMap.get(groupKey);
+            ArrayList<PlotComparisonItem> singleLineItems = new ArrayList<PlotComparisonItem>();
+
+            int numbOfAttacks = 0;
+            for (long time : recordMap.keySet()){
+                ArrayList<Record>list = recordMap.get(time);
+                if (list.size() == 0) continue;
+                PlotComparisonItem item = new PlotComparisonItem(this.getHourAsTimeString(time), 0 , (double)time, (double) list.size());
+                singleLineItems.add(item);
+                numbOfAttacks +=list.size();
+            }
+
+            Collections.sort(singleLineItems, new Comparator<PlotComparisonItem>() {
+                @Override
+                public int compare(PlotComparisonItem s1, PlotComparisonItem s2) {
+                    return s1.getValue1().compareTo(s2.getValue1());
+                }
+            });
+
+            double itemValue = (((double)numbOfAttacks / (double)records.size())*100.);
+            PlotComparisonItem item = new PlotComparisonItem(groupKey, this.getColor(index), (double) numbOfAttacks, itemValue);
+            item.setChildItems(singleLineItems);
+            plotItems.add(item);
+            index++;
+        }
+        Collections.sort(plotItems, new Comparator<PlotComparisonItem>() {
+            @Override
+            public int compare(PlotComparisonItem s1, PlotComparisonItem s2) {
+                return s2.getValue2().compareTo(s1.getValue2());
+            }
+        });
+        return plotItems;
+    }
+
+    /*
+    *  BAR PLOT DATA
+    */
+    /**Returns plotitems for the comparison "attacks per bssid"
+     * The returned data is resized to the specified limit.
+     * @return ArrayList of  {@link PlotComparisonItem PlotComparisonItems}
+    */
+    public ArrayList<PlotComparisonItem> attacksPerBSSID(String protocol){
+        LogFilter filter = new LogFilter();
+        ArrayList<String> protocollist = new ArrayList<String>();
+        filter.setAboveTimestamp(this.filter.getAboveTimestamp());
+        filter.setBelowTimestamp(this.filter.getBelowTimestamp());
+        filter.setBSSIDs(this.filter.getBSSIDs());
+        protocollist.add(protocol);
+        filter.setProtocols(protocollist);
+
+        ArrayList<PlotComparisonItem> plotItems = new ArrayList<PlotComparisonItem>();
+
+        HashMap<String, Integer> recordMap = new HashMap<String, Integer>();
+        ArrayList<Record> records = this.dbh.getRecordsForFilter(filter);
+        for (Record record : records){
+            int count = 0;
+            if (recordMap.containsKey(record.getBssid())){
+                count = recordMap.get(record.getBssid());
+            }
+            count++;
+            recordMap.put(record.getBssid(), count);
+        }
+        int index = 0;
+        for (String key : recordMap.keySet()){
+            double value = (double)recordMap.get(key);
+            if (value == 0.) continue;
+            PlotComparisonItem item = new PlotComparisonItem(key, this.getColor(index), 0., value);
+            plotItems.add(item);
+            index++;
+        }
+        Collections.sort(plotItems, new Comparator<PlotComparisonItem>() {
+            @Override
+            public int compare(PlotComparisonItem s1, PlotComparisonItem s2) {
+                return s2.getValue2().compareTo(s1.getValue2());
+            }
+        });
+        return this.resizeData(plotItems);
+    }
+    /**Returns plotitems for the comparison "attacks per essid"
+    * @return ArrayList of  {@link PlotComparisonItem PlotComparisonItems}
+    */
+    public ArrayList<PlotComparisonItem> attacksPerESSID(String protocol){
+        LogFilter filter = new LogFilter();
+        filter.setAboveTimestamp(this.filter.getAboveTimestamp());
+        filter.setBelowTimestamp(this.filter.getBelowTimestamp());
+        filter.setESSIDs(this.filter.getESSIDs());
+        ArrayList<String> protocollist = new ArrayList<String>();
+        protocollist.add(protocol);
+        filter.setProtocols(protocollist);
+
+        ArrayList<PlotComparisonItem> plotItems = new ArrayList<PlotComparisonItem>();
+
+        HashMap<String, Integer> recordMap = new HashMap<String, Integer>();
+        ArrayList<Record> records = this.dbh.getRecordsForFilter(filter);
+        for (Record record : records){
+            int count = 0;
+            if (recordMap.containsKey(record.getSsid())){
+                count = recordMap.get(record.getSsid());
+            }
+            count++;
+            recordMap.put(record.getSsid(), count);
+        }
+        int index = 0;
+        for (String key : recordMap.keySet()){
+            double value =  (double)recordMap.get(key);
+            if (value == 0.) continue;
+            PlotComparisonItem item = new PlotComparisonItem(key,this.getColor(index), 0. ,value);
+            plotItems.add(item);
+            index++;
+        }
+        Collections.sort(plotItems, new Comparator<PlotComparisonItem>() {
+            @Override
+            public int compare(PlotComparisonItem s1, PlotComparisonItem s2) {
+                return s2.getValue2().compareTo(s1.getValue2());
+            }
+        });
+
+        return this.resizeData(plotItems);
+    }
+
+    /**
+    * This will normalize the given list of plot items to the specified length of MAX_NUMBER_OF_CHART_OBJECTS.
+    * Creates an "others" group, containing all objects after the (MAX_NUMBER_OF_CHART_OBJECTS - 1)th object from the given list.
+    * If the given list does contain MAX_NUMBER_OF_CHART_OBJECTS+1 or more objects, nothing will change.
+    *
+    * @param plotItems to normalize  {@link PlotComparisonItem PlotComparisonItems}
+    * @return the normalized ArrayList of  {@link PlotComparisonItem PlotComparisonItems}
+    */
+    private ArrayList<PlotComparisonItem> resizeData(ArrayList<PlotComparisonItem> plotItems){
+        if (plotItems != null){
+            if (plotItems.size() > MAX_NUMBER_OF_CHART_OBJECTS && MAX_NUMBER_OF_CHART_OBJECTS > 1){
+                ArrayList<PlotComparisonItem> copy = new ArrayList<PlotComparisonItem>();
+                ArrayList<PlotComparisonItem> others = new ArrayList<PlotComparisonItem>();
+                double valueOfOthers = 0;
+
+                for (int i = 0; i < plotItems.size(); i++){
+                    if (i < MAX_NUMBER_OF_CHART_OBJECTS - 1){
+                        PlotComparisonItem item = plotItems.get(i);
+                        item.setColor(this.getColor(i));
+                        copy.add(plotItems.get(i));
+                    } else {
+                        PlotComparisonItem item = plotItems.get(i);
+                        others.add(item);
+                        valueOfOthers+=item.getValue2();
+                    }
+                }
+                PlotComparisonItem otherItem = new PlotComparisonItem(OTHER_CHART_TITLE, this.getOtherColor(), 0., valueOfOthers);
+                otherItem.setChildItems(others);
+                copy.add(otherItem);
+
+                Collections.sort(copy, new Comparator<PlotComparisonItem>() {
+                    @Override
+                    public int compare(PlotComparisonItem s1, PlotComparisonItem s2) {
+                        return s2.getValue2().compareTo(s1.getValue2());
+                    }
+                });
+
+                return copy;
+            }
+        }
+        return plotItems;
+    }
+
+    /*
+    * FILTER STUFF
+    * */
+
+    /**
+    * Returns the first selected protocol from all selected protocols.
+    * If no protocol is selected, it return the first protocol in the protocolTitles() list.
+    * @return String protocolName
+    * */
+    private String getCurrentSelectedProtocol(){
+         ArrayList<String> protocolTitles = this.getSelectedProtocolTitles();
+         if (protocolTitles != null && protocolTitles.size() != 0){
+             return  protocolTitles.get(0);
+         }
+         return this.protocolTitles().get(0);
+     }
+
+    /**
+     * Return all Protocols
+    *
+    * @return ArrayList<String> protocolNames
+    * */
+     public ArrayList<String> protocolTitles(){
+        ArrayList<String> titles = new ArrayList<String>();
+        for (String protocol : this.getResources().getStringArray(
+                R.array.protocols)) {
+            titles.add(protocol);
+        }
+
+	    titles.add("PORTSCAN");
+
+	    return titles;
+    }
+    /**
+    * Returns a boolean array containing a bool value for each protocol. If the value is true, the filter object contains the protocol.
+    * The array sequence equates to the protocolTitles() list.
+    * @return boolean[] selection array
+    * */
+    public boolean[] selectedProtocols(){
+        ArrayList<String> protocols = this.protocolTitles();
+        boolean[] selected = new boolean[protocols.size()];
+
+        int i = 0;
+        for(String protocol : protocols){
+            selected[i] =(this.filter.protocols.contains(protocol));
+            i++;
+        }
+        return selected;
+    }
+    public ArrayList<String> getSelectedProtocolTitles(){
+        ArrayList<String> knownProtocols = this.protocolTitles();
+        if (this.filter.hasProtocols()){
+            ArrayList<String> titles = new ArrayList<String>();
+            int i =0;
+            for (boolean b : this.selectedProtocols()){
+                if (b){
+                    String title = knownProtocols.get(i);
+                    titles.add(title);
+                }
+                i++;
+            }
+            return titles;
+        }
+        return this.protocolTitles();
+    }
+    /*
+    *
+    * COLOR STUFF
+    *
+    * */
+
+    /** Returns the color for the other group
+     * @return int color*/
+    public int getOtherColor(){
+        return Color.argb(255, 80, 80, 80); // grey
+	}
+    /** Returns the color for the given index
+     * @return int color*/
+    public Integer getColor(int index) {
+		return ColorSequenceGenerator.getColorForIndex(index);
+    }
+
+    /** Returns the Plot layout.
+     *
+     * @return LinearLayout plot layout
+     */
+    public LinearLayout getPlotLayout(){
+        if (this.rootView != null){
+            return (LinearLayout) this.rootView.findViewById(R.id.plot_layout);
+        } else {
+            return null;
+        }
+    }
+
+    /*
+     *
+     *  FILTER STUFF
+     *
+     * */
+    /**
+     * Returns true if the current filter is set for a given filter menu title.
+     * @param  title of the filter menu item {@link String String}
+     * @return boolean b
+     */
+     private boolean isFilterSetForTitle(String title){
+        if (title.equals(FILTER_MENU_TITLE_BSSID)){
+            return this.filter.hasBSSIDs();
+        }
+        if (title.equals(FILTER_MENU_TITLE_ESSID)){
+            return this.filter.hasESSIDs();
+        }
+        if (title.equals(FILTER_MENU_TITLE_PROTOCOLS)){
+            return (this.filter.getProtocols() != null  && this.filter.hasProtocols() && this.filter.getProtocols().size() != this.protocolTitles().size());
+        }
+        if (title.equals(FILTER_MENU_TITLE_TIMESTAMP_BELOW)){
+            return this.filter.hasBelowTimestamp();
+        }
+        if (title.equals(FILTER_MENU_TITLE_TIMESTAMP_ABOVE)){
+            return this.filter.hasAboveTimestamp();
+        }
+        return false;
+    }
+
+    /**
+     * Clears the current filter.
+     */
+    private void clearFilter(){
+        if(filter == null) this.filter = new LogFilter();
+        this.filter.clear();
+    }
+
+    /*
+    *
+    *  DATE TRANSFORMATION
+    *
+    */
+
+    /**
+     * Returns the current hour from a date.
+     * @param timeInMillis long
+     * @return milliseconds in long
+     */
+    public long getDayHourFromDate(long timeInMillis){
+
+        Calendar calendar = Calendar.getInstance();
+
+        calendar.setTimeInMillis (timeInMillis);
+        int hour    = calendar.get(Calendar.HOUR_OF_DAY);
+        //int min     = calendar.get(Calendar.MINUTE);
+
+        return hour;
+
+    }
+    /**
+     * Returns the current date without the seconds, minutes, hours.
+     * @param timeInMillis long
+     * @return long date with time 00:00:00
+     * */
+    public long getDateFromMilliseconds(long timeInMillis){
+        long millisInDay = 60 * 60 * 24 * 1000;
+        return (timeInMillis / millisInDay) * millisInDay;
+
+    }
+
+    /**
+    *  Returns the given hour as a formated string.
+     * Format: "HH:00"
+    * */
+    private String getHourAsTimeString(long hour) {
+        return "" + hour + ":00";
+    }
+
+    //static final DateFormat dateFormat = new SimpleDateFormat("d.M.yy");
+
+    /**Returns a date as a formated string
+     * @param timeStamp date
+     * @return String date format is localised*/
+    @SuppressLint("SimpleDateFormat")
+    private String getDateAsDayString(long timeStamp) {
+        try {
+            Date netDate = (new Date(timeStamp));
+            DateFormat dateFormat = android.text.format.DateFormat.getMediumDateFormat(this.getActivity());
+            return dateFormat.format(netDate);
+            //return dateFormat.format(netDate);
+        } catch (Exception ex) {
+            return "xx";
+        }
+    }
+
+    @SuppressLint("SimpleDateFormat")
+    /**Returns a date as a formated string
+     * @param long date
+     * @return String date format (H:mm  dd/MM/yyyy)*/
+    private String getDateAsString(long timeStamp) {
+        try {
+            DateFormat sdf = new SimpleDateFormat("H:mm  dd.MM.yyyy");
+            Date netDate = (new Date(timeStamp));
+            return sdf.format(netDate);
+        } catch (Exception ex) {
+            return "xx";
+        }
+    }
+
+
+    /**
+     * USERINTERACTION
+     */
+    /**
+     * Will be called if the users taps on a list row.
+     * @param index int
+     */
+    private void userTappedOnLegendItem(int index){
+        if (index < this.currentData.size()){
+            PlotComparisonItem item = this.currentData.get(index);
+            ArrayList<String> selectedData;
+            String groupingKey = null;
+            selectedData = new ArrayList<String>();
+
+            if (item.getChildItems() == null){
+                selectedData.add(item.getTitle());
+            } else {
+                for (PlotComparisonItem other : item.getChildItems()){
+                    selectedData.add(other.getTitle());
+                }
+            }
+            LogFilter filter = new LogFilter();
+            if (this.currentPlotView instanceof PieGraph){
+                filter.setProtocols(selectedData);
+                if(selectedData != null && selectedData.size() > 1){
+                    groupingKey = MainActivity.getInstance().getResources().getString(R.string.rec_protocol);
+                }
+            }
+            if (this.currentPlotView instanceof BarGraph){
+
+                if (this.selectedCompareData.equals(COMPARE_TITLE_AttacksPerESSID)){
+                    filter.setESSIDs(selectedData);
+                    groupingKey = MainActivity.getInstance().getResources().getString(R.string.ESSID);
+                } else {
+                    filter.setBSSIDs(selectedData);
+                    groupingKey = MainActivity.getInstance().getResources().getString(R.string.BSSID);
+
+                }
+                ArrayList<String> currentSelectedProtocol = new ArrayList<String>();
+                currentSelectedProtocol.add(this.getCurrentSelectedProtocol());
+                filter.setProtocols(currentSelectedProtocol);
+            }
+            if (this.currentPlotView instanceof  LineGraph){
+                selectedData = new ArrayList<String>();
+                selectedData.add(item.getTitle());
+                filter.setESSIDs(selectedData);
+                filter.setProtocols(this.filter.getProtocols());
+                groupingKey = MainActivity.getInstance().getResources().getString(R.string.ESSID);
+            }
+
+            if (this.filter.hasATimestamp()){
+                filter.setAboveTimestamp(this.filter.getAboveTimestamp());
+                filter.setBelowTimestamp(this.filter.getBelowTimestamp());
+            }
+
+            this.pushRecordOverviewForFilter(filter, groupingKey);
+        }
+    }
+
+    /**Will be called if the user clicked on a slice
+     * @param index of the slice (int)*/
+    public void onSliceClick(int index){
+    }
+    /**Will be called if the user clicked on a bar
+     * @param index of the bar (int)*/
+    public void onBarClick(int index){
+        this.userTappedOnLegendItem(index);
+    }
+
+    /**
+     * Displays a record over view fragment.
+     * @param filter  {@link de.tudarmstadt.informatik.hostage.ui2.model.LogFilter LogFilter}
+     * @param groupingKey String, key to group the attack list in the RecordOverview
+     */
+    private void pushRecordOverviewForFilter(LogFilter filter, String groupingKey){
+
+        // Get the FragmentManager from the MainActivity.
+        // The FragmentManager handles every pushing / popping action of a Fragment.
+        FragmentManager fm = this.getActivity().getFragmentManager();
+
+        if (fm != null){
+            // Create a new instance of your Fragment.
+            RecordOverviewFragment newFragment = new RecordOverviewFragment();
+            // Set true, if the user can navigate backwards from the new pushed fragment.
+	        newFragment.setUpNavigatible(true);
+
+            // Set a Filter Object if needed.
+            // Otherwise the RecordOverviewFragment will display all possible records / attacks.
+            // With the filter object you also can change the sorting, by changing the sorttype of it.
+            if (filter != null) newFragment.setFilter(filter);
+
+            // Set a grouping key, if you want a other grouping behaviour than the default (timestamp).
+            if (groupingKey != null && groupingKey.length() != 0) newFragment.setGroupKey(groupingKey);
+
+            // Push new Fragment
+            MainActivity.getInstance().injectFragment(newFragment);
+
+        }
+    }
+
+
+}

+ 428 - 0
src/de/tudarmstadt/informatik/hostage/ui/fragment/ThreatMapFragment.java

@@ -0,0 +1,428 @@
+package de.tudarmstadt.informatik.hostage.ui2.fragment;
+
+import static com.google.android.gms.common.GooglePlayServicesUtil.getErrorDialog;
+import static com.google.android.gms.common.GooglePlayServicesUtil.isGooglePlayServicesAvailable;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Fragment;
+import android.app.FragmentManager;
+import android.content.DialogInterface;
+import android.graphics.Color;
+import android.location.Location;
+import android.os.Bundle;
+import android.view.InflateException;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import com.google.android.gms.common.ConnectionResult;
+import com.google.android.gms.common.GooglePlayServicesClient;
+import com.google.android.gms.location.LocationClient;
+import com.google.android.gms.location.LocationListener;
+import com.google.android.gms.location.LocationRequest;
+import com.google.android.gms.maps.CameraUpdateFactory;
+import com.google.android.gms.maps.GoogleMap;
+import com.google.android.gms.maps.MapFragment;
+import com.google.android.gms.maps.model.BitmapDescriptor;
+import com.google.android.gms.maps.model.BitmapDescriptorFactory;
+import com.google.android.gms.maps.model.CircleOptions;
+import com.google.android.gms.maps.model.LatLng;
+import com.google.android.gms.maps.model.Marker;
+import com.google.android.gms.maps.model.MarkerOptions;
+
+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.persistence.HostageDBOpenHelper;
+import de.tudarmstadt.informatik.hostage.ui2.model.LogFilter;
+import de.tudarmstadt.informatik.hostage.ui2.activity.MainActivity;
+
+/**
+ * ThreatMapFragment
+ *
+ * Created by Fabio Arnold on 10.02.14.
+ */
+public class ThreatMapFragment extends TrackerFragment implements GoogleMap.OnInfoWindowClickListener,
+		GooglePlayServicesClient.ConnectionCallbacks,
+		GooglePlayServicesClient.OnConnectionFailedListener,
+		LocationListener {
+
+	private static GoogleMap sMap = null;
+
+	private static View sView = null;
+
+	private static Thread mLoader = null;
+
+	private static HashMap<String, String> sMarkerIDToSSID = new HashMap<String, String>();
+
+	private LocationClient mLocationClient;
+
+	private static final LocationRequest REQUEST = LocationRequest.create()
+			.setExpirationDuration(5000) // 5 seconds
+			.setInterval(5000)           // 5 seconds
+			.setFastestInterval(16)      // 16ms = 60fps
+			.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
+
+	/**
+	 * if google play services aren't available an error notification will be displayed
+	 *
+	 * @return true if the google play services are available
+	 */
+	private boolean isGooglePlay() {
+		int status = isGooglePlayServicesAvailable(getActivity());
+		boolean result = status == ConnectionResult.SUCCESS;
+		if (!result) {
+			getErrorDialog(status, getActivity(), 10).show();
+		}
+		return result;
+	}
+
+	/**
+	 * callback for when the info window of a marker gets clicked
+	 * open the RecordOverviewFragment and display all records belonging to an SSID
+	 *
+	 * @param marker this info window belongs to
+	 */
+	@Override
+	public void onInfoWindowClick(Marker marker) {
+		//MainActivity.getInstance().displayView(MainActivity.MainMenuItem.RECORDS.getValue());
+		//RecordOverviewFragment recordOverviewFragment = (RecordOverviewFragment)MainActivity.getInstance().getCurrentFragment();
+		//if (recordOverviewFragment != null) {
+		String ssid = sMarkerIDToSSID.get(marker.getId());
+
+		ArrayList<String> ssids = new ArrayList<String>();
+		ssids.add(ssid);
+
+		LogFilter filter = new LogFilter();
+		filter.setESSIDs(ssids);
+
+		RecordOverviewFragment recordOverviewFragment = new RecordOverviewFragment();
+		recordOverviewFragment.setFilter(filter);
+		recordOverviewFragment.setGroupKey("ESSID");
+		recordOverviewFragment.setAllowBack(true);
+
+		MainActivity.getInstance().injectFragment(recordOverviewFragment);
+		//recordOverviewFragment.showDetailsForSSID(getActivity(), ssid);
+		//}
+	}
+
+	/**
+	 * callbacks from LocationClient
+	 */
+	@Override
+	public void onConnected(Bundle bundle) {
+		mLocationClient.requestLocationUpdates(REQUEST, this);
+	}
+
+	@Override
+	public void onDisconnected() {
+
+	}
+
+	@Override
+	public void onConnectionFailed(ConnectionResult connectionResult) {
+
+	}
+
+	@Override
+	public void onLocationChanged(Location location) {
+		sMap.animateCamera(CameraUpdateFactory.newLatLng(
+				new LatLng(location.getLatitude(), location.getLongitude())));
+	}
+
+	/**
+	 * helper class
+	 * easier to use than LatLng
+	 */
+	private class Point {
+
+		public double x, y;
+
+		public Point(double sx, double sy) {
+			x = sx;
+			y = sy;
+		}
+	}
+
+	/**
+	 * helper class
+	 * contains heuristic to split SSIDs by location
+	 * see MAX_DISTANCE
+	 */
+	private class SSIDArea {
+
+		private Point mMinimum, mMaximum;
+
+		public int numPoints;
+
+		public static final int MAX_NUM_ATTACKS = 20;
+
+		public static final float MAX_DISTANCE = 1000.0f; // 1km
+
+		public SSIDArea(LatLng initialLocation) {
+			//mMinimum = new Point(360.0, 360.0);
+			//mMaximum = new Point(-360.0, -360.0);
+			mMinimum = new Point(initialLocation.latitude, initialLocation.longitude);
+			mMaximum = new Point(initialLocation.latitude, initialLocation.longitude);
+			numPoints = 1;
+		}
+
+		public boolean doesLocationBelongToArea(LatLng location) {
+			LatLng center = calculateCenterLocation();
+			float[] result = new float[1];
+			Location.distanceBetween(center.latitude, center.longitude, location.latitude,
+					location.longitude, result);
+			return result[0] < MAX_DISTANCE;
+		}
+
+		public void addLocation(LatLng location) {
+			Point point = new Point(location.latitude, location.longitude);
+			if (point.x < mMinimum.x) {
+				mMinimum.x = point.x;
+			}
+			if (point.x > mMaximum.x) {
+				mMaximum.x = point.x;
+			}
+			if (point.y < mMinimum.y) {
+				mMinimum.y = point.y;
+			}
+			if (point.y > mMaximum.y) {
+				mMaximum.y = point.y;
+			}
+			numPoints++;
+		}
+
+		public LatLng calculateCenterLocation() {
+			return new LatLng(0.5 * (mMinimum.x + mMaximum.x), 0.5 * (mMinimum.y + mMaximum.y));
+		}
+
+		public float calculateRadius() {
+			float[] result = new float[1];
+			Location.distanceBetween(mMinimum.x, mMinimum.y, mMaximum.x, mMaximum.y, result);
+			return 0.5f * result[0];
+		}
+
+		public int calculateColor() {
+			int threatLevel = numPoints;
+			if (threatLevel > MAX_NUM_ATTACKS) {
+				threatLevel = MAX_NUM_ATTACKS;
+			}
+			float alpha = 1.0f - (float) (threatLevel - 1) / (float) (MAX_NUM_ATTACKS - 1);
+			return Color.argb(127, (int) (240.0 + 15.0 * alpha), (int) (80.0 + 175.0 * alpha), 60);
+		}
+	}
+
+	/**
+	 * fills the map with markers and circle representing SSIDs
+	 * does it asynchronously in background thread
+	 */
+	private void populateMap() {
+		if (mLoader != null) {
+			mLoader.interrupt();
+		}
+		mLoader = new Thread(new Runnable() {
+			private void updateUI(final HashMap<String, ArrayList<SSIDArea>> threatAreas) {
+				if (mLoader.isInterrupted()) {
+					return;
+				}
+
+				Activity activity = getActivity();
+				if (activity != null) {
+					activity.runOnUiThread(new Runnable() {
+						@Override
+						public void run() {
+							sMap.clear();
+
+							CircleOptions circleOptions = new CircleOptions().radius(200.0)
+									.fillColor(Color.argb(127, 240, 80, 60)).strokeWidth(0.0f);
+							BitmapDescriptor bitmapDescriptor = BitmapDescriptorFactory
+									.fromResource(R.drawable.wifi_marker);
+							for (Map.Entry<String, ArrayList<SSIDArea>> entry : threatAreas.entrySet()) {
+								String ssid = entry.getKey();
+								ArrayList<SSIDArea> areas = entry.getValue();
+
+								for (SSIDArea area : areas) {
+									int color = area.calculateColor();
+									LatLng center = area.calculateCenterLocation();
+									float radius = area.calculateRadius();
+
+									sMap.addCircle(circleOptions.center(center).radius(100.0 + radius)
+											.fillColor(color));
+									Marker marker = sMap.addMarker(new MarkerOptions()
+											.title(ssid + ": " + area.numPoints + (area.numPoints == 1
+													? getResources()
+													.getString(R.string.attack)
+													: getResources().getString(R.string.attacks))).position(
+													center));
+									marker.setIcon(bitmapDescriptor);
+
+									sMarkerIDToSSID.put(marker.getId(), ssid);
+								}
+							}
+
+						}
+					});
+				}
+			}
+
+			private HashMap<String, ArrayList<SSIDArea>> doInBackground() {
+				HostageDBOpenHelper dbh = new HostageDBOpenHelper(getActivity());
+				ArrayList<Record> records = dbh.getRecordsForFilter(new LogFilter());
+
+				HashMap<String, ArrayList<SSIDArea>> threatAreas
+						= new HashMap<String, ArrayList<SSIDArea>>();
+
+				for (Record record : records) {
+					LatLng location = new LatLng(record.getLatitude(), record.getLongitude());
+					//Log.i("location", "lat: " + location.latitude + " long: " + location.longitude);
+					ArrayList<SSIDArea> areas;
+					if (threatAreas.containsKey(record.getSsid())) {
+						areas = threatAreas.get(record.getSsid());
+						boolean foundArea = false;
+						for (SSIDArea area : areas) {
+							if (area.doesLocationBelongToArea(location)) {
+								area.addLocation(location);
+								foundArea = true;
+								break;
+							}
+						}
+						if (!foundArea) {
+							areas.add(new SSIDArea(location));
+						}
+					} else {
+						areas = new ArrayList<SSIDArea>();
+						areas.add(new SSIDArea(location));
+						threatAreas.put(record.getSsid(), areas);
+					}
+				}
+
+				return threatAreas;
+			}
+
+			@Override
+			public void run() {
+				updateUI(doInBackground());
+			}
+		});
+
+		mLoader.start(); // run!
+	}
+
+	/**
+	 * performs initialization
+	 * checks if google play services are supported
+	 * view must be removed if this object has been created once before
+	 * that is why view is static
+	 *
+	 * @param inflater           the inflater
+	 * @param container          the container
+	 * @param savedInstanceState the savedInstanceState
+	 * @return the view
+	 */
+	@Override
+	public View onCreateView(final LayoutInflater inflater, ViewGroup container,
+			Bundle savedInstanceState) {
+		super.onCreateView(inflater, container, savedInstanceState);
+
+		final Activity activity = getActivity();
+		if (activity != null) {
+			activity.setTitle(getResources().getString(R.string.drawer_threat_map));
+		}
+
+		if (sView != null) {
+			ViewGroup parent = (ViewGroup) sView.getParent();
+			if (parent != null) {
+				parent.removeView(sView);
+			}
+		}
+
+		try {
+			sView = inflater.inflate(R.layout.fragment_threatmap, container, false);
+			if (isGooglePlay()) {
+				final FragmentManager fragmentManager = getFragmentManager();
+				if (fragmentManager != null) {
+					final MapFragment mapFragment = (MapFragment) getFragmentManager()
+							.findFragmentById(R.id.threatmapfragment);
+					if (mapFragment != null) {
+						sMap = mapFragment.getMap();
+					}
+				}
+			}
+		} catch (InflateException e) {
+			// map already exists
+			//e.printStackTrace();
+		}
+
+		if (sMap != null) {
+			sMap.setOnInfoWindowClickListener(this);
+			// custom info window layout
+			sMap.setInfoWindowAdapter(new GoogleMap.InfoWindowAdapter() {
+				@Override
+				public View getInfoWindow(Marker marker) {
+					return null;
+				}
+
+				@Override
+				public View getInfoContents(Marker marker) {
+					View view = inflater.inflate(R.layout.fragment_threatmap_infowindow, null);
+					if (view != null) {
+						TextView titleTextView = (TextView) view
+								.findViewById(R.id.threatmap_infowindow_title);
+						if (titleTextView != null) {
+							titleTextView.setText(marker.getTitle());
+						}
+					}
+					return view;
+				}
+			});
+
+			sMap.setMyLocationEnabled(true);
+
+			LatLng tudarmstadt = new LatLng(49.86923, 8.6632768); // default location
+			sMap.moveCamera(CameraUpdateFactory.newLatLngZoom(tudarmstadt, 13));
+
+			populateMap();
+		}
+
+		// tell the user to enable wifi so map data can be streamed
+		if (activity != null && !HelperUtils.isNetworkAvailable(activity)) {
+			new AlertDialog.Builder(activity)
+					.setTitle(R.string.information)
+					.setMessage(R.string.no_network_connection_threatmap_msg)
+					.setPositiveButton(android.R.string.ok,
+							new DialogInterface.OnClickListener() {
+								public void onClick(DialogInterface dialog,
+										int which) {
+								}
+							}
+					)
+					.setIcon(android.R.drawable.ic_dialog_info).show();
+		}
+
+		return sView;
+	}
+
+	@Override
+	public void onResume() {
+		super.onResume();
+		if (mLocationClient == null) {
+			mLocationClient = new LocationClient(MainActivity.getInstance().getApplicationContext(),
+					this, this);
+		}
+		mLocationClient.connect();
+	}
+
+	@Override
+	public void onPause() {
+		super.onPause();
+		if (mLocationClient != null) {
+			mLocationClient.disconnect();
+		}
+	}
+}

+ 35 - 0
src/de/tudarmstadt/informatik/hostage/ui/fragment/TrackerFragment.java

@@ -0,0 +1,35 @@
+package de.tudarmstadt.informatik.hostage.ui2.fragment;
+
+import com.google.android.gms.analytics.HitBuilders;
+import com.google.android.gms.analytics.Tracker;
+
+import android.app.Activity;
+import android.app.Fragment;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import de.tudarmstadt.informatik.hostage.HostageApplication;
+
+/**
+ * @author Alexander Brakowski
+ * @created 01.04.14 19:04
+ */
+public class TrackerFragment extends Fragment {
+	@Override
+	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+		View v = super.onCreateView(inflater, container, savedInstanceState);
+
+		final Activity activity = getActivity();
+
+		if (activity != null) {
+			// tracking stuff
+			Tracker t = ((HostageApplication) activity.getApplication()).getTracker();
+			t.setScreenName(this.getClass().getName());
+			t.send(new HitBuilders.AppViewBuilder().build());
+		}
+
+		return v;
+	}
+}

+ 66 - 0
src/de/tudarmstadt/informatik/hostage/ui/fragment/UpNavigatibleFragment.java

@@ -0,0 +1,66 @@
+package de.tudarmstadt.informatik.hostage.ui2.fragment;
+
+import android.app.Fragment;
+
+/**
+ * This abstract fragments allows the definition of an child - parent relation of fragments. It is necessary for the app to allow Up navigation of fragments.
+ *
+ * @author Alexander Brakowski
+ * @created 12.03.14 16:20
+ */
+public abstract class UpNavigatibleFragment extends TrackerFragment {
+	/**
+	 * Holds a reference to the parent fragment
+	 */
+	private Class<?> mUpFragment;
+
+	/**
+	 * Indicates whether the fragment is up navigatible
+	 */
+	private boolean mIsUpNavigatible = false;
+
+	private boolean mAllowBack = false;
+
+	/**
+	 * Retrieves the parent fragment to be used for up navigation
+	 * @return the parent fragment
+	 */
+	public Class<?> getUpFragment(){
+		return mUpFragment;
+	}
+
+	/**
+	 * Sets the parent fragment of this fragment.
+	 * @param upFragment the fragment to set as parent
+	 */
+	public void setUpFragment(Class<?> upFragment){
+		this.mUpFragment = upFragment;
+	}
+
+	/**
+	 * Checks whether this fragment can be navigated up
+	 *
+	 * @return true if this fragment can be up navigated,
+	 *         false otherwise
+	 */
+	public boolean isUpNavigatible(){
+		return mIsUpNavigatible;
+	}
+
+	/**
+	 * Sets the state of up navigation for this fragment
+	 * @param isUpNavigatible true to allow up navigation
+	 *                        false no up navigation
+	 */
+	public void setUpNavigatible(boolean isUpNavigatible){
+		this.mIsUpNavigatible = isUpNavigatible;
+	}
+
+	public boolean getAllowBack(){
+		return mAllowBack;
+	}
+
+	public void setAllowBack(boolean allowBack){
+		this.mAllowBack = allowBack;
+	}
+}

+ 380 - 0
src/de/tudarmstadt/informatik/hostage/ui/fragment/opengl/AnimatedMesh.java

@@ -0,0 +1,380 @@
+package de.tudarmstadt.informatik.hostage.ui2.fragment.opengl;
+
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+import java.nio.ShortBuffer;
+import java.util.ArrayList;
+
+import android.opengl.GLES20;
+import android.opengl.Matrix;
+import android.util.Log;
+
+/**
+ * @author Fabio Arnold
+ *
+ * Animated Mesh
+ * This class reads a mesh in the AMSH binary format and creates the necessary OpenGL objects for drawing
+ */
+
+public class AnimatedMesh {
+	private ByteBuffer data;
+	
+	private int vertexOffset;
+	private int vertexSize;
+	private int triangleOffset;
+	private int triangleCount;
+	
+	private int vertexBuffer; // vbo
+	private int indexBuffer;
+
+	private ArrayList<Bone> bones;
+	private float[] matrices; // matrix palette for skinning
+	
+	private ArrayList<Action> actions;
+	private Action currentAction;
+	private int currentFrame;
+	private boolean loopAction = false;
+	private boolean reverseAction = false;
+
+	/**
+	 * start play an animation (action)
+	 * @param actionName name in the AMSH file
+	 * @param loop loop the animation
+	 * @param reverse play the animation backwards
+	 */
+	public void startAction(String actionName, boolean loop, boolean reverse) {
+		if (!(currentAction != null && currentAction.name.equals(actionName) && reverse)) // keep the current frame
+			currentFrame = 0;
+		loopAction = loop;
+		reverseAction = reverse;
+		currentAction = null;
+		// find the action
+		for (Action action : actions) {
+			if (action.name.equals(actionName)) {
+				currentAction = action;
+				break;
+			}
+		}
+		if (currentAction != null && reverseAction)
+			if (!(currentAction != null && currentAction.name.equals(actionName) && reverse)) // keep the current frame
+				currentFrame = currentAction.numFrames - 1;
+	}
+
+	/**
+	 * @return true if completed OR hasn't started yet.
+	 */
+	public boolean isActionDone() {
+		if (currentAction == null)
+			return true;
+		return currentFrame <= 1 || currentFrame >= currentAction.numFrames - 1;
+		/*
+		if (reverseAction)
+			return currentFrame <= 0;
+		else
+			return currentFrame >= currentAction.numFrames - 1;
+			*/
+	}
+
+	// private classes. don't use these.
+
+	private class Bone {
+		@SuppressWarnings("unused")
+		public String name; // 15 bytes
+		public int parentIndex; // 1 byte
+		public float[] invBindPose; // 64 bytes
+		
+		Bone(ByteBuffer data) {
+			name = "";
+			boolean stop = false;
+			for (int i = 0; i < 15; i++) {
+				char c;
+				if ((c = (char)data.get()) == '\0') stop = true;
+				if (!stop) name += c;
+			}
+			// Log.i("bone", name);
+			parentIndex = (int)data.get();
+			invBindPose = new float[16];
+			data.asFloatBuffer().get(invBindPose);
+			data.position(data.position() + 64);
+		}
+	}
+	
+	private class Action {
+		public String name; // 16 bytes
+		public int numFrames;
+		public ArrayList<Track> tracks;
+		
+		public static final int kHeaderSize = 28;
+		
+		Action(ByteBuffer data) {
+			name = "";
+			boolean stop = false;
+			for (int i = 0; i < 16; i++) {
+				char c;
+				if ((c = (char)data.get()) == '\0') stop = true;
+				if (!stop) name += c;
+			}
+			Log.i("action", name);
+			numFrames = data.getInt();
+			int trackOffset = data.getInt();
+			int trackCount = data.getInt();
+			tracks = new ArrayList<Track>();
+			for (int i = 0; i < trackCount; i++) {
+				data.position(trackOffset + i * Track.kHeaderSize);
+				tracks.add(new Track(data));
+			}
+		}
+	}
+	
+	private class Track {
+		@SuppressWarnings("unused")
+		public int boneIndex;
+		public ArrayList<JointPose> poses;
+		
+		public static final int kHeaderSize = 12;
+		
+		Track(ByteBuffer data) {
+			boneIndex = data.getInt();
+			int jointPoseOffset = data.getInt();
+			int jointPoseCount = data.getInt();
+			poses = new ArrayList<JointPose>();
+			data.position(jointPoseOffset);
+			for (int i = 0; i < jointPoseCount; i++) {
+				//data.position(jointPoseOffset + i * JointPose::kSize); // joint pose size == 32
+				poses.add(new JointPose(data));
+			}
+		}
+	}
+	
+	private class JointPose {
+		public Quaternion rotation;
+		public float[] translation;
+		@SuppressWarnings("unused")
+		float scale;
+		
+		public static final int kSize = 32;
+		
+		JointPose() { // empty pose == identity
+			rotation = new Quaternion();
+			translation = new float[3];
+			translation[0] = translation[1] = translation[2] = 0.0f;
+			scale = 1.0f;
+		}
+		
+		JointPose(ByteBuffer data) {
+			FloatBuffer floatData = data.asFloatBuffer();
+			data.position(data.position() + kSize);
+ 
+			// quat data is x y z w, because of glm
+			float x = floatData.get();
+			float y = floatData.get();
+			float z = floatData.get();
+			float w = floatData.get();
+			rotation = new Quaternion(w, x, y, z);
+			translation = new float[3];
+			floatData.get(translation);
+			scale = floatData.get();
+		}
+		
+		float[] toMatrix() { // TODO: scale
+			float[] matrix = new float[16];
+			Matrix.setIdentityM(matrix, 0);
+
+			Quaternion q = rotation;
+			matrix[0 * 4 + 0] = 1.0f - 2.0f * q.y * q.y - 2.0f * q.z * q.z;
+			matrix[0 * 4 + 1] = 2.0f * q.x * q.y + 2.0f * q.w * q.z;
+			matrix[0 * 4 + 2] = 2.0f * q.x * q.z - 2.0f * q.w * q.y;
+
+			matrix[1 * 4 + 0] = 2.0f * q.x * q.y - 2.0f * q.w * q.z;
+			matrix[1 * 4 + 1] = 1.0f - 2.0f * q.x * q.x - 2.0f * q.z * q.z;
+			matrix[1 * 4 + 2] = 2.0f * q.y * q.z + 2.0f * q.w * q.x;
+
+			matrix[2 * 4 + 0] = 2.0f * q.x * q.z + 2 * q.w * q.y;
+			matrix[2 * 4 + 1] = 2.0f * q.y * q.z - 2 * q.w * q.x;
+			matrix[2 * 4 + 2] = 1.0f - 2.0f * q.x * q.x - 2.0f * q.y * q.y;
+
+			matrix[3 * 4 + 0] = translation[0];
+			matrix[3 * 4 + 1] = translation[1];
+			matrix[3 * 4 + 2] = translation[2];
+			
+			return matrix;
+		}
+	}
+
+	/**
+	 * create an animmesh from an inputstream
+	 * @param is the inputstream
+	 */
+	public AnimatedMesh(InputStream is) {
+		ByteArrayOutputStream out = new ByteArrayOutputStream();
+		try {
+			final int EOF = -1;
+			int len;
+			byte[] buffer = new byte[1 << 12];
+			while (EOF != (len = is.read(buffer)))
+				out.write(buffer, 0, len);
+		} catch (IOException e) {
+			e.printStackTrace();
+			return;
+		}
+
+		//data = ByteBuffer.wrap(out.toByteArray()); // doesn't work data needs to be direct
+		data = ByteBuffer.allocateDirect(out.size());
+		data.order(ByteOrder.nativeOrder());
+		data.put(out.toByteArray());
+		data.position(0);
+
+		// header
+		int magicNum = data.getInt();
+		int version = data.getInt();
+		//assert(magicNum == ('A' << 24 | 'M' << 16 | 'S' << 8 | 'H') && version == 1);
+		
+		vertexSize = 48;
+		vertexOffset = data.getInt();
+		int vertexCount = data.getInt();
+		triangleOffset = data.getInt();
+		triangleCount = data.getInt();
+		int boneOffset = data.getInt();
+		int boneCount = data.getInt();
+		int actionOffset = data.getInt();
+		int actionCount = data.getInt();
+		
+		// vertices and indices data
+		IntBuffer buffers = IntBuffer.allocate(2);
+		GLES20.glGenBuffers(2, buffers); // buffer names
+		vertexBuffer = buffers.get();
+		indexBuffer = buffers.get();
+
+		data.position(vertexOffset);
+		GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vertexBuffer);
+		GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, vertexSize * vertexCount, data.asFloatBuffer(), GLES20.GL_STATIC_DRAW);
+		GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
+
+		// convert int indices to short
+		// TODO: more efficient way?
+		data.position(triangleOffset);
+		ShortBuffer indexBufferData = ShortBuffer.allocate(3 * triangleCount);
+		for (int i = 0; i < 3 * triangleCount; i++)
+			indexBufferData.put((short)data.getInt());
+		indexBufferData.position(0);
+		
+		GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
+		GLES20.glBufferData(GLES20.GL_ELEMENT_ARRAY_BUFFER, 6 * triangleCount, indexBufferData, GLES20.GL_STATIC_DRAW);
+		GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
+		
+		// bones
+		bones = new ArrayList<Bone>();
+		data.position(boneOffset);
+		for (int i = 0; i < boneCount; i++)
+			bones.add(new Bone(data));
+		
+		matrices = new float[16 * boneCount];
+		
+		// actions
+		actions = new ArrayList<Action>();
+		for (int i = 0; i < actionCount; i++) {
+			data.position(actionOffset + i * Action.kHeaderSize); // action header size == 28
+			actions.add(new Action(data));
+		}
+		
+		currentAction = null;
+		currentFrame = 0;
+		loopAction = false;
+	}
+	
+	public static float[] addVec3(final float[] v1, final float[] v2) {
+		float[] v3 = new float[3];
+		v3[0] = v1[0] + v2[0];
+		v3[1] = v1[1] + v2[1];
+		v3[2] = v1[2] + v2[2];
+		return v3;
+	}
+
+	/**
+	 * update the bone transforms of the mesh and advance one frame
+	 */
+	public void tick() {
+		// empty pose
+		ArrayList<JointPose> pose = new ArrayList<JointPose>();
+		for (int i = 0; i < bones.size(); i++)
+			pose.add(new JointPose());
+		
+		if (currentAction != null) {
+			// fill pose with action
+			for (int i = 0; i < currentAction.tracks.size(); i++) {
+				// TODO: do lerp or something nice
+				pose.get(i).rotation = currentAction.tracks.get(i).poses.get(currentFrame).rotation;
+				pose.get(i).translation = currentAction.tracks.get(i).poses.get(currentFrame).translation;
+			}
+
+			// advance one frame
+			if (reverseAction) {
+				if (currentFrame > 0) {
+					currentFrame--;
+				} else if (loopAction) {
+					currentFrame = currentAction.numFrames - 1;
+				}
+			} else {
+				if (currentFrame < currentAction.numFrames - 1) {
+					currentFrame++;
+				} else if (loopAction) {
+					currentFrame = 0;
+				}
+			}
+		}
+		
+		// convert pose to skinning matrices
+		for (int i = 0; i < bones.size(); i++) {
+			int parentIndex = bones.get(i).parentIndex;
+			if (parentIndex != -1) { // bone has parent
+				JointPose parentPose = pose.get(parentIndex);
+				pose.get(i).rotation = parentPose.rotation.multiply(pose.get(i).rotation);
+				pose.get(i).translation = addVec3(parentPose.translation, parentPose.rotation.multiply(pose.get(i).translation));
+			}
+			Matrix.multiplyMM(matrices, i * 16, pose.get(i).toMatrix(), 0, bones.get(i).invBindPose, 0);
+		}
+	}
+	
+	/**
+	 * draws the mesh
+	 * @param program the currently bound shader program
+	 */
+	public void draw(int program) {
+		GLES20.glUniformMatrix4fv(GLES20.glGetUniformLocation(program, "boneMatrices"), bones.size(), false, matrices, 0);
+		
+		// TODO: cache attrib locations
+		int positionIndex = GLES20.glGetAttribLocation(program, "position");
+		int normalIndex = GLES20.glGetAttribLocation(program, "normal");
+		int texCoordIndex = GLES20.glGetAttribLocation(program, "texCoord");
+		int boneIndicesIndex = GLES20.glGetAttribLocation(program, "boneIndices");
+		int boneWeightsIndex = GLES20.glGetAttribLocation(program, "boneWeights");
+		
+		GLES20.glEnableVertexAttribArray(positionIndex);
+		GLES20.glEnableVertexAttribArray(normalIndex);
+		GLES20.glEnableVertexAttribArray(texCoordIndex);
+		GLES20.glEnableVertexAttribArray(boneIndicesIndex);
+		GLES20.glEnableVertexAttribArray(boneWeightsIndex);
+		
+		GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vertexBuffer);
+		GLES20.glVertexAttribPointer(positionIndex, 3, GLES20.GL_FLOAT, false, vertexSize, 0);
+		GLES20.glVertexAttribPointer(normalIndex, 3, GLES20.GL_FLOAT, false, vertexSize, 12);
+		GLES20.glVertexAttribPointer(texCoordIndex, 2, GLES20.GL_FLOAT, false, vertexSize, 24);
+		GLES20.glVertexAttribPointer(boneIndicesIndex, 4, GLES20.GL_UNSIGNED_BYTE, false, vertexSize, 32);
+		GLES20.glVertexAttribPointer(boneWeightsIndex, 3, GLES20.GL_FLOAT, false, vertexSize, 36);
+		GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
+		GLES20.glDrawElements(GLES20.GL_TRIANGLES, 3 * triangleCount, GLES20.GL_UNSIGNED_SHORT, 0);
+		GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
+		GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
+		
+		GLES20.glDisableVertexAttribArray(positionIndex);
+		GLES20.glDisableVertexAttribArray(normalIndex);
+		GLES20.glDisableVertexAttribArray(texCoordIndex);
+		GLES20.glDisableVertexAttribArray(boneIndicesIndex);
+		GLES20.glDisableVertexAttribArray(boneWeightsIndex);
+	}
+}

+ 41 - 0
src/de/tudarmstadt/informatik/hostage/ui/fragment/opengl/HomeGLSurfaceView.java

@@ -0,0 +1,41 @@
+package de.tudarmstadt.informatik.hostage.ui2.fragment.opengl;
+
+import android.content.Context;
+import android.opengl.GLSurfaceView;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.MotionEvent;
+
+/**
+ * the gl surface view used in the homefragment layout
+ * creates the threat indicator renderer
+ */
+public class HomeGLSurfaceView extends GLSurfaceView {
+	public HomeGLSurfaceView(Context context) { // won't be called
+		super(context);
+		Log.e("gl", "called wrong constructor (w/o attributes)");
+	}
+	
+	// this constructor will be called
+	public HomeGLSurfaceView(Context context, AttributeSet attrs) {
+		super(context, attrs);
+		setEGLContextClientVersion(2); // OpenGL ES 2.0
+		// setZOrderOnTop(true);
+		// transparency
+		// setEGLConfigChooser(8, 8, 8, 8, 16, 0);
+		// getHolder().setFormat(PixelFormat.RGBA_8888);
+		setRenderer(new ThreatIndicatorGLRenderer());
+	}
+	
+	// TODO: just for testing -> remove this eventually
+	/*@Override
+	public boolean onTouchEvent(MotionEvent event) {
+		if (event.getAction() == MotionEvent.ACTION_DOWN) {
+			ThreatIndicatorGLRenderer.ThreatLevel threatLevel = ThreatIndicatorGLRenderer.ThreatLevel.NO_THREAT;
+			if (event.getX() > 0.5f * getWidth()) threatLevel = ThreatIndicatorGLRenderer.ThreatLevel.PAST_THREAT;
+			if (event.getY() > 0.5f * getHeight()) threatLevel = ThreatIndicatorGLRenderer.ThreatLevel.LIVE_THREAT;
+			ThreatIndicatorGLRenderer.setThreatLevel(threatLevel);
+		}
+		return false;
+	}*/
+}

+ 70 - 0
src/de/tudarmstadt/informatik/hostage/ui/fragment/opengl/Quaternion.java

@@ -0,0 +1,70 @@
+package de.tudarmstadt.informatik.hostage.ui2.fragment.opengl;
+
+/**
+ * some basic quaternion class because android doesn't provide any
+ */
+public class Quaternion {
+	public float w, x, y, z;
+	
+	Quaternion() { // identity
+		w = 1.0f; x = y = z = 0.0f;
+	}
+	
+	Quaternion(float w, float x, float y, float z) {
+		this.w = w;
+		this.x = x;
+		this.y = y;
+		this.z = z;
+	}
+	
+	public Quaternion clone() {
+		return new Quaternion(w, x, y, z);
+	}
+	
+	public Quaternion multiply(final Quaternion p) {
+		Quaternion q = this;
+		return new Quaternion(
+				q.w * p.w - q.x * p.x - q.y * p.y - q.z * p.z,
+				q.w * p.x + q.x * p.w + q.y * p.z - q.z * p.y,
+				q.w * p.y + q.y * p.w + q.z * p.x - q.x * p.z,
+				q.w * p.z + q.z * p.w + q.x * p.y - q.y * p.x);
+	}
+	
+	public static float[] cross(final float[] v1, final float[] v2) {
+		float[] v3 = new float[3];
+		v3[0] = v1[1] * v2[2] - v1[2] * v2[1];
+		v3[1] = v1[2] * v2[0] - v1[0] * v2[2];
+		v3[2] = v1[0] * v2[1] - v1[1] * v2[0];	
+		return v3;
+	}
+	
+	public static float[] multiply(final float s, final float[] v) {
+		float[] result = new float[3];
+		result[0] = s * v[0];
+		result[1] = s * v[1];
+		result[2] = s * v[2];
+		return result;
+	}
+	
+	public static float[] add(final float[] v1, final float[] v2) {
+		float[] v3 = new float[3];
+		v3[0] = v1[0] + v2[0];
+		v3[1] = v1[1] + v2[1];
+		v3[2] = v1[2] + v2[2];
+		return v3;
+	}
+	
+	public float[] multiply(final float[] v) { // rotate a point
+		Quaternion q = this;
+		float[] axis = new float[3];
+		axis[0] = q.x; axis[1] = q.y; axis[2] = q.z;
+		
+		float[] uv = cross(axis, v);
+		float[] uuv = cross(axis, uv);
+		
+		uv = multiply(2.0f * q.w, uv);
+		uuv = multiply(2.0f, uuv);
+
+		return add(v, add(uv, uuv));
+	}
+}

+ 359 - 0
src/de/tudarmstadt/informatik/hostage/ui/fragment/opengl/ThreatIndicatorGLRenderer.java

@@ -0,0 +1,359 @@
+package de.tudarmstadt.informatik.hostage.ui2.fragment.opengl;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Scanner;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+import android.content.res.AssetManager;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Color;
+
+import android.opengl.GLES20;
+import android.opengl.GLSurfaceView.Renderer;
+import android.opengl.GLUtils;
+import android.opengl.Matrix;
+import android.util.Log;
+
+/**
+ * @author Fabio Arnold
+ * 
+ * ThreatIndicatorGLRenderer
+ * This class is responsible for drawing an animation representing the current threat level.
+ * Use the method setThreatLevel to set the state (0 to 3).
+ */
+
+public class ThreatIndicatorGLRenderer implements Renderer {
+	public enum ThreatLevel {
+		NOT_MONITORING,
+		NO_THREAT,
+		PAST_THREAT,
+		LIVE_THREAT
+	}
+	
+	/**
+	 * Set the threat level which should be indicated
+	 * @param threatLevel
+	 */
+	public static void setThreatLevel(ThreatLevel threatLevel) {
+		mNextThreatLevel = threatLevel;
+	}
+
+	/**
+	 * Match the background color of the view holding this renderer
+	 * @param color 32 bit integer encoding the color
+	 */
+	public static void setBackgroundColor(int color) {
+		mBackgroundColor[0] = (float)Color.red(color) / 255.0f;
+		mBackgroundColor[1] = (float)Color.green(color) / 255.0f;
+		mBackgroundColor[2] = (float)Color.blue(color) / 255.0f;
+	}
+	private static float[] mBackgroundColor = new float[3];
+	
+	public static AssetManager assets = null; // needs to be set by the Activity using this class
+
+	// OpenGL data
+	private int mProgram;
+	private float [] mModelview;
+	private float [] mProjection;
+	private float [] mMVP;
+	
+	private AnimatedMesh androidMesh = null;
+	private AnimatedMesh beeMesh = null;
+	private int androidTexture;
+	private int beeTexture;
+	
+	// threat state
+	private static ThreatLevel mNextThreatLevel = ThreatLevel.NO_THREAT;
+	
+	private ThreatLevel mCurrentThreatLevel = ThreatLevel.NO_THREAT;
+	private ThreatLevel mTargetThreatLevel = ThreatLevel.NO_THREAT;
+	private float mThreatLevelTransition = 1.0f; // 1.0 means transition is complete
+
+	private static boolean sPlayGreetingAnimation = true; // greet the first time
+
+	private long mStartTimeMillis; // for animation
+	public ThreatIndicatorGLRenderer() {
+		mStartTimeMillis = System.currentTimeMillis();
+	}
+	
+	/**
+	 * Initialization will be called after GL context is created and is current
+	 */
+	public void onSurfaceCreated(GL10 arg0, EGLConfig arg1) {
+		GLES20.glClearColor(mBackgroundColor[0], mBackgroundColor[1], mBackgroundColor[2], 1.0f);
+		GLES20.glEnable(GLES20.GL_DEPTH_TEST);
+		GLES20.glEnable(GLES20.GL_CULL_FACE);
+		GLES20.glEnable(GLES20.GL_TEXTURE_2D);
+		
+		try {
+			InputStream is = assets.open("meshes/android.amh");
+			androidMesh = new AnimatedMesh(is);
+			/* play the greeting animation the first time the gets opened
+			   not each time the threatindicator gets created */
+			if (sPlayGreetingAnimation) {
+				androidMesh.startAction("greet", false, false);
+				sPlayGreetingAnimation = false;
+			} else if (mCurrentThreatLevel == ThreatLevel.NO_THREAT) { // default state
+				androidMesh.startAction("happy", true, false); // play NO_THREAT animation
+			}
+		} catch (IOException e) {
+			Log.e("gl", "Couldn't open android mesh");
+		}
+		androidTexture = loadTexture("textures/android-tex.png");
+		try {
+			InputStream is = assets.open("meshes/bee.amh");
+			beeMesh = new AnimatedMesh(is);
+			beeMesh.startAction("bee_armatureAct", true, false);
+		} catch (IOException e) {
+			Log.e("gl", "Couldn't open bee mesh");
+		}
+		beeTexture = loadTexture("textures/bee-tex.png");
+		
+		mModelview = new float[16];
+		Matrix.setIdentityM(mModelview, 0);
+		mProjection = new float[16];
+		mMVP = new float[16];
+		
+		// default shader
+		String vertexSource = "attribute vec3 position; void main() {gl_Position = vec4(position, 1.0);}";
+		String fragmentSource = "void main() {gl_FragColor = vec4(1.0, 0.0, 1.0, 1.0);}";
+		try {
+			vertexSource = inputStreamToString(assets.open("shaders/skinned.vert"));
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+		try {fragmentSource = inputStreamToString(assets.open("shaders/skinned.frag"));
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+		mProgram = loadProgram(vertexSource, fragmentSource);
+	}
+	
+	/**
+	 * Tries to render at 30 Hz (see bottom part)
+	 */
+	public void onDrawFrame(GL10 arg0) {
+		long timeMillis = System.currentTimeMillis() - mStartTimeMillis;
+		double animTime = 0.001 * (double)timeMillis; // in seconds
+		
+		// threat level state machine
+		if (mTargetThreatLevel != mCurrentThreatLevel) {
+			boolean blocked = false; // block until current action is completed
+			if (mThreatLevelTransition == 0.0f) {
+				if (androidMesh.isActionDone()) {
+					switch (mTargetThreatLevel) {
+					case NOT_MONITORING:
+						androidMesh.startAction("sleep", false, false);
+						break;
+					case NO_THREAT:
+						androidMesh.startAction("happy", true, false);
+						break;
+					case PAST_THREAT:
+						androidMesh.startAction("fear", true, false);
+						break;
+					case LIVE_THREAT:
+						androidMesh.startAction("panic", true, false);
+						break;
+					}
+				} else blocked = true;
+			}
+			
+			if (!blocked) {
+				mThreatLevelTransition += 0.016f;
+				if (mThreatLevelTransition >= 1.0f) {
+					mCurrentThreatLevel = mTargetThreatLevel;
+					mThreatLevelTransition = 1.0f;
+				}
+			}
+		} else {
+			if (mNextThreatLevel != mTargetThreatLevel) {
+				mTargetThreatLevel = mNextThreatLevel;
+				mThreatLevelTransition = 0.0f;
+				
+				// HACK!!! reverses the sleep animation to create smooth transition into other states
+				if (mCurrentThreatLevel == ThreatLevel.NOT_MONITORING)
+					androidMesh.startAction("sleep", false, true);
+			}
+		}
+		
+		androidMesh.tick(); // animate android
+		
+		// OpenGL drawing
+		GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
+		
+		GLES20.glUseProgram(mProgram);
+		int colorUniformLoc = GLES20.glGetUniformLocation(mProgram, "color");
+		int textureUniformLoc = GLES20.glGetUniformLocation(mProgram, "texture");
+		int mvpUniformLoc = GLES20.glGetUniformLocation(mProgram, "mvp");
+
+		//  animate color
+		final float[] whiteColor = {1.0f, 1.0f, 1.0f, 1.0f};
+		final float[] greyColor = {0.5f, 0.5f, 0.5f, 1.0f};
+		final float[] redColor = {2.0f, 0.4f, 0.2f, 1.0f};
+		final float[] yellowColor = {1.1f * 255.0f / 166.0f, 1.2f * 255.0f / 200.0f, 0.0f, 1.0f};
+		
+		float[] currentColor = whiteColor;
+		float blink = 0.5f + 0.5f * (float)Math.sin(12.0 * animTime);
+		switch (mCurrentThreatLevel) {
+		case NOT_MONITORING:
+			currentColor = greyColor;
+			break;
+		case PAST_THREAT:
+			currentColor = mixColor(blink, whiteColor, yellowColor);
+			break;
+		case LIVE_THREAT:
+			currentColor = mixColor(blink, whiteColor, redColor);
+			break;
+		}
+		if (mTargetThreatLevel != mCurrentThreatLevel) {
+			float[] targetColor = whiteColor;
+			switch (mTargetThreatLevel) {
+			case NOT_MONITORING:
+				targetColor = greyColor;
+				break;
+			case PAST_THREAT:
+				targetColor = mixColor(blink, whiteColor, yellowColor);
+				break;
+			case LIVE_THREAT:
+				targetColor = mixColor(blink, whiteColor, redColor);
+				break;
+			}
+			currentColor = mixColor(mThreatLevelTransition, currentColor, targetColor);
+		}
+		GLES20.glUniform4fv(colorUniformLoc, 1, currentColor, 0);
+		GLES20.glUniform1i(textureUniformLoc, 0);
+		
+		// animate camera
+		Matrix.setIdentityM(mModelview, 0);
+		if (mCurrentThreatLevel == ThreatLevel.LIVE_THREAT || mTargetThreatLevel == ThreatLevel.LIVE_THREAT) {
+			float delta = 1.0f;
+			if (mThreatLevelTransition < 0.4f) { // animate only during the first 40% of the transition
+				delta = mThreatLevelTransition / 0.4f;
+				delta = -2.0f * delta * delta * delta + 3.0f * delta * delta; // ease in/out
+			}
+			if (mTargetThreatLevel != ThreatLevel.LIVE_THREAT)
+				delta = 1.0f - delta;
+			Matrix.translateM(mModelview, 0, 0.0f, -0.6f - 0.2f * delta, -1.6f - 0.4f * delta); // 0.0f, -0.8f, -2.0f
+			Matrix.rotateM(mModelview, 0, -85.0f + 5.0f * delta, 1.0f, 0.0f, 0.0f); // -80.0f
+			
+		} else {
+			Matrix.translateM(mModelview, 0, 0.0f, -0.6f, -1.6f);
+			Matrix.rotateM(mModelview, 0, -85.0f, 1.0f, 0.0f, 0.0f);
+		}
+		Matrix.multiplyMM(mMVP, 0, mProjection, 0, mModelview, 0);
+		GLES20.glUniformMatrix4fv(mvpUniformLoc, 1, false, mMVP, 0);
+		
+		GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, androidTexture);
+		androidMesh.draw(mProgram);
+		
+		// restore color
+		GLES20.glUniform4fv(colorUniformLoc, 1, whiteColor, 0);
+
+		if (mCurrentThreatLevel == ThreatLevel.LIVE_THREAT || mTargetThreatLevel == ThreatLevel.LIVE_THREAT) {
+			// draw a bee rotating around the android
+			
+			float fadeIn = mThreatLevelTransition;
+			if (mTargetThreatLevel != ThreatLevel.LIVE_THREAT) fadeIn = 1.0f - fadeIn; // fade out
+			float beePositionZ = 2.0f * (1.0f - fadeIn) * (1.0f - fadeIn); // animate the bee going in/out
+			
+			final float beeSize = 0.2f;
+			Matrix.rotateM(mModelview, 0, (float)((-240.0 * animTime) % 360.0), 0.0f, 0.0f, 1.0f); // rotate around android
+			Matrix.translateM(mModelview, 0, 0.6f, 0.0f, 0.7f + 0.1f * (float)Math.sin(12.0 * animTime) + beePositionZ); // go up and down
+			Matrix.rotateM(mModelview, 0, 20.0f * (float)Math.cos(12.0 * animTime), 1.0f, 0.0f, 0.0f); // rock back and forth
+			Matrix.scaleM(mModelview, 0, beeSize, beeSize, beeSize);
+			Matrix.multiplyMM(mMVP, 0, mProjection, 0, mModelview, 0);
+			GLES20.glUniformMatrix4fv(mvpUniformLoc, 1, false, mMVP, 0);
+	
+			GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, beeTexture);
+			beeMesh.tick();
+			beeMesh.draw(mProgram);
+		}
+		
+		long deltaTime = System.currentTimeMillis() - mStartTimeMillis - timeMillis; // time for one frame
+		if (deltaTime < 33) {
+			try {
+				Thread.sleep(33 - deltaTime); // sleep remaining time for 30 Hz
+			} catch (InterruptedException e) {
+				e.printStackTrace();
+			}
+		}
+	}
+
+	/**
+	 * Informs renderer of changed surface dimensions
+	 */
+	public void onSurfaceChanged(GL10 arg0, int w, int h) {
+		int width = w;
+		int height = h;
+		float aspectRatio = (float) w / (float) h;
+		//Matrix.orthoM(mProjection, 0, -aspectRatio, aspectRatio, -1.0f, 1.0f, -1.0f, 1.0f);
+		float near = 0.1f;
+		float fov = 2.0f;
+		Matrix.frustumM(mProjection, 0, near * -aspectRatio, near * aspectRatio, -near, near, fov * near, 100.0f);
+		GLES20.glViewport(0, 0, width, height);
+	}
+	
+	// some private helper methods
+	
+	private float[] mixColor(float alpha, float[] color1, float[] color2) {
+		float[] color3 = new float[4];
+		color3[0] = (1.0f - alpha) * color1[0] + alpha * color2[0];
+		color3[1] = (1.0f - alpha) * color1[1] + alpha * color2[1];
+		color3[2] = (1.0f - alpha) * color1[2] + alpha * color2[2];
+		color3[3] = (1.0f - alpha) * color1[3] + alpha * color2[3];
+		return color3;
+	}
+	
+	private int loadTexture(String filePath) {
+		Bitmap bitmap;
+		try {
+			bitmap = BitmapFactory.decodeStream(assets.open(filePath));
+		} catch (IOException e) {
+			e.printStackTrace();
+			return 0;
+		}
+		
+		int[] names = {0};
+		GLES20.glGenTextures(1, names, 0);
+		int tex = names[0];
+		GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, tex);
+
+		GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
+		GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
+		GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
+		bitmap.recycle(); // memory is now gpu -> free it
+		
+		GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, tex);
+		
+		return tex;
+	}
+	
+	// see http://stackoverflow.com/questions/309424/read-convert-an-inputstream-to-a-string
+	private static String inputStreamToString(InputStream is) {
+	    Scanner scanner = new Scanner(is);
+		Scanner s = scanner.useDelimiter("\\A");
+	    String result = s.hasNext() ? s.next() : "";
+	    scanner.close();
+	    return result;
+	}
+	
+	private static int loadShader(int type, String source) {
+		int shader = GLES20.glCreateShader(type);
+		GLES20.glShaderSource(shader, source);
+		GLES20.glCompileShader(shader);
+		Log.i("gl", GLES20.glGetShaderInfoLog(shader));
+		return shader;
+	}
+	
+	private static int loadProgram(String vertexSource, String fragmentSource) {
+		int program = GLES20.glCreateProgram();
+		GLES20.glAttachShader(program, loadShader(GLES20.GL_VERTEX_SHADER, vertexSource));
+		GLES20.glAttachShader(program, loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource));
+		GLES20.glLinkProgram(program);
+		return program;
+	}
+}

+ 26 - 0
src/de/tudarmstadt/informatik/hostage/ui/helper/ColorSequenceGenerator.java

@@ -0,0 +1,26 @@
+package de.tudarmstadt.informatik.hostage.ui2.helper;
+
+import android.graphics.Color;
+
+/**
+ * Idea from http://ridiculousfish.com/blog/posts/colors.html
+ * Created by Fabio Arnold on 25.02.14.
+ */
+public class ColorSequenceGenerator {
+	private static final int BIT_COUNT = 30; // sadly there is no unsigned type in java
+	public static int getColorForIndex(int index) {
+		int reverseIndex = 0;
+		for (int i = 0; i  < BIT_COUNT; i++) {
+			reverseIndex = (reverseIndex << 1) | (index & 1);
+			index >>= 1;
+		}
+		float hue = ((float)reverseIndex / (float)(1 << BIT_COUNT) + 0.0f) % 1.0f;
+
+		float[] hsv = new float[3];
+		hsv[0] = 360.0f * hue;
+		hsv[1] = 0.7f; // not fully saturated
+		hsv[2] = 0.9f;
+
+		return Color.HSVToColor(hsv);
+	}
+}

+ 337 - 0
src/de/tudarmstadt/informatik/hostage/ui/layouts/FlowLayout.java

@@ -0,0 +1,337 @@
+/**
+ * Copyright (c) 2011, Artem Votincev (apmem.org)
+ * http://www.apache.org/licenses/LICENSE-2.0.txt
+ *
+ * Modified by Alexander Brakowski for the purpose of this project
+ */
+package de.tudarmstadt.informatik.hostage.ui2.layouts;
+
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import de.tudarmstadt.informatik.hostage.R;
+
+/**
+ * Subviews of this View will be positioned in an "flowing" manner.
+ *
+ * See {@link https://github.com/ApmeM/android-flowlayout}
+ */
+public class FlowLayout extends ViewGroup {
+	public static final int HORIZONTAL = 0;
+	public static final int VERTICAL = 1;
+	private int horizontalSpacing = 0;
+	private int verticalSpacing = 0;
+	private int orientation = 0;
+	private boolean debugDraw = false;
+
+	public FlowLayout(Context context) {
+		super(context);
+
+		this.readStyleParameters(context, null);
+	}
+
+	public FlowLayout(Context context, AttributeSet attributeSet) {
+		super(context, attributeSet);
+
+		this.readStyleParameters(context, attributeSet);
+	}
+
+	public FlowLayout(Context context, AttributeSet attributeSet, int defStyle) {
+		super(context, attributeSet, defStyle);
+
+		this.readStyleParameters(context, attributeSet);
+	}
+
+	@Override
+	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+		int sizeWidth = MeasureSpec.getSize(widthMeasureSpec) - this.getPaddingRight() - this.getPaddingLeft();
+		int sizeHeight = MeasureSpec.getSize(heightMeasureSpec) - this.getPaddingTop() - this.getPaddingBottom();
+
+		int modeWidth = MeasureSpec.getMode(widthMeasureSpec);
+		int modeHeight = MeasureSpec.getMode(heightMeasureSpec);
+
+		int size;
+		int mode;
+
+		if (orientation == HORIZONTAL) {
+			size = sizeWidth;
+			mode = modeWidth;
+		} else {
+			size = sizeHeight;
+			mode = modeHeight;
+		}
+
+		int lineThicknessWithSpacing = 0;
+		int lineThickness = 0;
+		int lineLengthWithSpacing = 0;
+		int lineLength;
+
+		int prevLinePosition = 0;
+
+		int controlMaxLength = 0;
+		int controlMaxThickness = 0;
+
+		final int count = getChildCount();
+		for (int i = 0; i < count; i++) {
+			final View child = getChildAt(i);
+			if (child.getVisibility() == GONE) {
+				continue;
+			}
+
+			LayoutParams lp = (LayoutParams) child.getLayoutParams();
+
+			child.measure(
+					getChildMeasureSpec(widthMeasureSpec, this.getPaddingLeft() + this.getPaddingRight(), lp.width),
+					getChildMeasureSpec(heightMeasureSpec, this.getPaddingTop() + this.getPaddingBottom(), lp.height)
+			);
+
+			int hSpacing = this.getHorizontalSpacing(lp);
+			int vSpacing = this.getVerticalSpacing(lp);
+
+			int childWidth = child.getMeasuredWidth();
+			int childHeight = child.getMeasuredHeight();
+
+			int childLength;
+			int childThickness;
+			int spacingLength;
+			int spacingThickness;
+
+			if (orientation == HORIZONTAL) {
+				childLength = childWidth;
+				childThickness = childHeight;
+				spacingLength = hSpacing;
+				spacingThickness = vSpacing;
+			} else {
+				childLength = childHeight;
+				childThickness = childWidth;
+				spacingLength = vSpacing;
+				spacingThickness = hSpacing;
+			}
+
+			lineLength = lineLengthWithSpacing + childLength;
+			lineLengthWithSpacing = lineLength + spacingLength;
+
+			boolean newLine = lp.newLine || (mode != MeasureSpec.UNSPECIFIED && lineLength > size);
+			if (newLine) {
+				prevLinePosition = prevLinePosition + lineThicknessWithSpacing;
+
+				lineThickness = childThickness;
+				lineLength = childLength;
+				lineThicknessWithSpacing = childThickness + spacingThickness;
+				lineLengthWithSpacing = lineLength + spacingLength;
+			}
+
+			lineThicknessWithSpacing = Math.max(lineThicknessWithSpacing, childThickness + spacingThickness);
+			lineThickness = Math.max(lineThickness, childThickness);
+
+			int posX;
+			int posY;
+			if (orientation == HORIZONTAL) {
+				posX = getPaddingLeft() + lineLength - childLength;
+				posY = getPaddingTop() + prevLinePosition;
+			} else {
+				posX = getPaddingLeft() + prevLinePosition;
+				posY = getPaddingTop() + lineLength - childHeight;
+			}
+			lp.setPosition(posX, posY);
+
+			controlMaxLength = Math.max(controlMaxLength, lineLength);
+			controlMaxThickness = prevLinePosition + lineThickness;
+		}
+
+        /* need to take paddings into account */
+		if (orientation == HORIZONTAL) {
+			controlMaxLength += getPaddingLeft() + getPaddingRight();
+			controlMaxThickness += getPaddingBottom() + getPaddingTop();
+		} else {
+			controlMaxLength += getPaddingBottom() + getPaddingTop();
+			controlMaxThickness += getPaddingLeft() + getPaddingRight();
+		}
+
+		if (orientation == HORIZONTAL) {
+			this.setMeasuredDimension(resolveSize(controlMaxLength, widthMeasureSpec), resolveSize(controlMaxThickness, heightMeasureSpec));
+		} else {
+			this.setMeasuredDimension(resolveSize(controlMaxThickness, widthMeasureSpec), resolveSize(controlMaxLength, heightMeasureSpec));
+		}
+	}
+
+	private int getVerticalSpacing(LayoutParams lp) {
+		int vSpacing;
+		if (lp.verticalSpacingSpecified()) {
+			vSpacing = lp.verticalSpacing;
+		} else {
+			vSpacing = this.verticalSpacing;
+		}
+		return vSpacing;
+	}
+
+	private int getHorizontalSpacing(LayoutParams lp) {
+		int hSpacing;
+		if (lp.horizontalSpacingSpecified()) {
+			hSpacing = lp.horizontalSpacing;
+		} else {
+			hSpacing = this.horizontalSpacing;
+		}
+		return hSpacing;
+	}
+
+	@Override
+	protected void onLayout(boolean changed, int l, int t, int r, int b) {
+		final int count = getChildCount();
+		for (int i = 0; i < count; i++) {
+			View child = getChildAt(i);
+			LayoutParams lp = (LayoutParams) child.getLayoutParams();
+			child.layout(lp.x, lp.y, lp.x + child.getMeasuredWidth(), lp.y + child.getMeasuredHeight());
+		}
+	}
+
+	@Override
+	protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
+		boolean more = super.drawChild(canvas, child, drawingTime);
+		this.drawDebugInfo(canvas, child);
+		return more;
+	}
+
+	@Override
+	protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
+		return p instanceof LayoutParams;
+	}
+
+	@Override
+	protected LayoutParams generateDefaultLayoutParams() {
+		return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+	}
+
+	@Override
+	public LayoutParams generateLayoutParams(AttributeSet attributeSet) {
+		return new LayoutParams(getContext(), attributeSet);
+	}
+
+	@Override
+	protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
+		return new LayoutParams(p);
+	}
+
+	private void readStyleParameters(Context context, AttributeSet attributeSet) {
+		TypedArray a = context.obtainStyledAttributes(attributeSet, R.styleable.FlowLayout);
+		try {
+			horizontalSpacing = a.getDimensionPixelSize(R.styleable.FlowLayout_horizontalSpacing, 0);
+			verticalSpacing = a.getDimensionPixelSize(R.styleable.FlowLayout_verticalSpacing, 0);
+			orientation = a.getInteger(R.styleable.FlowLayout_orientation, HORIZONTAL);
+			debugDraw = a.getBoolean(R.styleable.FlowLayout_debugDraw, false);
+		} finally {
+			a.recycle();
+		}
+	}
+
+	private void drawDebugInfo(Canvas canvas, View child) {
+		if (!debugDraw) {
+			return;
+		}
+
+		Paint childPaint = this.createPaint(0xffffff00);
+		Paint layoutPaint = this.createPaint(0xff00ff00);
+		Paint newLinePaint = this.createPaint(0xffff0000);
+
+		LayoutParams lp = (LayoutParams) child.getLayoutParams();
+
+		if (lp.horizontalSpacing > 0) {
+			float x = child.getRight();
+			float y = child.getTop() + child.getHeight() / 2.0f;
+			canvas.drawLine(x, y, x + lp.horizontalSpacing, y, childPaint);
+			canvas.drawLine(x + lp.horizontalSpacing - 4.0f, y - 4.0f, x + lp.horizontalSpacing, y, childPaint);
+			canvas.drawLine(x + lp.horizontalSpacing - 4.0f, y + 4.0f, x + lp.horizontalSpacing, y, childPaint);
+		} else if (this.horizontalSpacing > 0) {
+			float x = child.getRight();
+			float y = child.getTop() + child.getHeight() / 2.0f;
+			canvas.drawLine(x, y, x + this.horizontalSpacing, y, layoutPaint);
+			canvas.drawLine(x + this.horizontalSpacing - 4.0f, y - 4.0f, x + this.horizontalSpacing, y, layoutPaint);
+			canvas.drawLine(x + this.horizontalSpacing - 4.0f, y + 4.0f, x + this.horizontalSpacing, y, layoutPaint);
+		}
+
+		if (lp.verticalSpacing > 0) {
+			float x = child.getLeft() + child.getWidth() / 2.0f;
+			float y = child.getBottom();
+			canvas.drawLine(x, y, x, y + lp.verticalSpacing, childPaint);
+			canvas.drawLine(x - 4.0f, y + lp.verticalSpacing - 4.0f, x, y + lp.verticalSpacing, childPaint);
+			canvas.drawLine(x + 4.0f, y + lp.verticalSpacing - 4.0f, x, y + lp.verticalSpacing, childPaint);
+		} else if (this.verticalSpacing > 0) {
+			float x = child.getLeft() + child.getWidth() / 2.0f;
+			float y = child.getBottom();
+			canvas.drawLine(x, y, x, y + this.verticalSpacing, layoutPaint);
+			canvas.drawLine(x - 4.0f, y + this.verticalSpacing - 4.0f, x, y + this.verticalSpacing, layoutPaint);
+			canvas.drawLine(x + 4.0f, y + this.verticalSpacing - 4.0f, x, y + this.verticalSpacing, layoutPaint);
+		}
+
+		if (lp.newLine) {
+			if (orientation == HORIZONTAL) {
+				float x = child.getLeft();
+				float y = child.getTop() + child.getHeight() / 2.0f;
+				canvas.drawLine(x, y - 6.0f, x, y + 6.0f, newLinePaint);
+			} else {
+				float x = child.getLeft() + child.getWidth() / 2.0f;
+				float y = child.getTop();
+				canvas.drawLine(x - 6.0f, y, x + 6.0f, y, newLinePaint);
+			}
+		}
+	}
+
+	private Paint createPaint(int color) {
+		Paint paint = new Paint();
+		paint.setAntiAlias(true);
+		paint.setColor(color);
+		paint.setStrokeWidth(2.0f);
+		return paint;
+	}
+
+	public static class LayoutParams extends ViewGroup.LayoutParams {
+		private static int NO_SPACING = -1;
+		private int x;
+		private int y;
+		private int horizontalSpacing = NO_SPACING;
+		private int verticalSpacing = NO_SPACING;
+		private boolean newLine = false;
+
+		public LayoutParams(Context context, AttributeSet attributeSet) {
+			super(context, attributeSet);
+			this.readStyleParameters(context, attributeSet);
+		}
+
+		public LayoutParams(int width, int height) {
+			super(width, height);
+		}
+
+		public LayoutParams(ViewGroup.LayoutParams layoutParams) {
+			super(layoutParams);
+		}
+
+		public boolean horizontalSpacingSpecified() {
+			return horizontalSpacing != NO_SPACING;
+		}
+
+		public boolean verticalSpacingSpecified() {
+			return verticalSpacing != NO_SPACING;
+		}
+
+		public void setPosition(int x, int y) {
+			this.x = x;
+			this.y = y;
+		}
+
+		private void readStyleParameters(Context context, AttributeSet attributeSet) {
+			TypedArray a = context.obtainStyledAttributes(attributeSet, R.styleable.FlowLayout_LayoutParams);
+			try {
+				horizontalSpacing = a.getDimensionPixelSize(R.styleable.FlowLayout_LayoutParams_layout_horizontalSpacing, NO_SPACING);
+				verticalSpacing = a.getDimensionPixelSize(R.styleable.FlowLayout_LayoutParams_layout_verticalSpacing, NO_SPACING);
+				newLine = a.getBoolean(R.styleable.FlowLayout_LayoutParams_layout_newLine, false);
+			} finally {
+				a.recycle();
+			}
+		}
+	}
+}

+ 28 - 0
src/de/tudarmstadt/informatik/hostage/ui/model/DrawerListItem.java

@@ -0,0 +1,28 @@
+package de.tudarmstadt.informatik.hostage.ui2.model;
+
+import android.widget.ImageView;
+import android.widget.TextView;
+
+/**
+ * Holds the data for an navigation item in the navigation drawer
+ *
+ * @author Alexander Brakowski
+ * @created 13.01.14 16:37
+ */
+public class DrawerListItem {
+
+	/**
+	 * The icon of the item
+	 */
+    public int icon;
+
+	/**
+	 * The text of the item
+	 */
+    public int text;
+
+    public DrawerListItem(int text, int icon){
+        this.text = text;
+        this.icon = icon;
+    }
+}

+ 41 - 0
src/de/tudarmstadt/informatik/hostage/ui/model/ExpandableListItem.java

@@ -0,0 +1,41 @@
+package de.tudarmstadt.informatik.hostage.ui2.model;
+
+import java.util.HashMap;
+
+
+/**
+ * Created by Julien on 06.02.14.
+ */
+public class ExpandableListItem {
+
+    /*Mapping Data Key To ViewID*/
+    public HashMap<String, Integer> id_Mapping;
+
+    /*Data Key To Textual Information*/
+    public HashMap<String, String> data;
+
+    public long getTag() {
+        return tag;
+    }
+    public void setTag(long tag) {
+        this.tag = tag;
+    }
+
+    private long tag;
+
+
+
+    public HashMap<String, Integer> getId_Mapping() {
+        return id_Mapping;
+    }
+    public void setId_Mapping(HashMap<String, Integer> id_Mapping) {
+        this.id_Mapping = id_Mapping;
+    }
+
+    public HashMap<String, String> getData(){
+        return this.data;
+    }
+    public void setData(HashMap<String, String> _data){
+        this.data = _data;
+    }
+}

+ 366 - 0
src/de/tudarmstadt/informatik/hostage/ui/model/LogFilter.java

@@ -0,0 +1,366 @@
+package de.tudarmstadt.informatik.hostage.ui2.model;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+public class LogFilter implements Parcelable {
+
+	public final static String LOG_FILTER_INTENT_KEY = "de.tudarmstadt.informatik.hostage.logfilter";
+
+	//private static final String TIMESTAMP_BELOW_KEY = "de.tudarmstadt.informatik.hostage.logfilter.timestampbelow";
+	//private static final String TIMESTAMP_ABOVE_KEY = "de.tudarmstadt.informatik.hostage.logfilter.timestampabove";
+	private static final String PROTOCOLS_KEY = "de.tudarmstadt.informatik.hostage.logfilter.protocols";
+	private static final String ESSID_KEY = "de.tudarmstadt.informatik.hostage.logfilter.essid";
+	private static final String BSSID_KEY = "de.tudarmstadt.informatik.hostage.logfilter.bssid";
+	//private static final String SORTTYPE_KEY = "de.tudarmstadt.informatik.hostage.logfilter.sorttype";
+
+    /**
+     * The SortType
+     */
+	public enum SortType {
+		packet_timestamp(0), protocol(1), ssid(2), _bssid(3), _attack_id(7), _id(8);
+		private final int id;
+
+		SortType(int id) {
+			this.id = id;
+		}
+
+		public int getValue() {
+			return id;
+		}
+	}
+
+	public ArrayList<String> BSSIDs;
+	public ArrayList<String> ESSIDs;
+	public ArrayList<String> protocols;
+
+	public boolean isNotEditable;
+
+	public SortType sorttype;
+
+	public long belowTimestamp;
+	public long aboveTimestamp;
+
+    /**
+     * Constructur
+     */
+	public LogFilter() {
+		this.clear();
+	}
+
+    /**
+     * Clears / resets all attributes of the filter objects
+     * The below timestamp will be maximal and the above timestamp will be minimal (long).
+     * The sort type is set to the default: timestamp
+     */
+	public void clear() {
+		this.belowTimestamp = Long.MAX_VALUE;
+		this.aboveTimestamp = Long.MIN_VALUE;
+		this.sorttype = SortType.packet_timestamp;
+		this.BSSIDs = new ArrayList<String>();
+		this.ESSIDs = new ArrayList<String>();
+		this.protocols = new ArrayList<String>();
+	}
+
+    @Override
+	public int describeContents() {
+		return 0;
+	}
+
+	// write filter's data to the passed-in Parcel
+    @Override
+	public void writeToParcel(Parcel out, int flags) {
+		HashMap<String, ArrayList<String>> values = new HashMap<String, ArrayList<String>>();
+		if (this.BSSIDs != null && this.BSSIDs.size() > 0) {
+			values.put(BSSID_KEY, this.getBSSIDs());
+		}
+		if (this.ESSIDs != null && this.ESSIDs.size() > 0) {
+			values.put(ESSID_KEY, this.getESSIDs());
+		}
+		if (this.protocols != null && this.protocols.size() > 0) {
+			values.put(PROTOCOLS_KEY, this.getProtocols());
+		}
+		long timeArray[] = new long[] { this.aboveTimestamp, this.belowTimestamp };
+		out.writeMap(values);
+		out.writeInt(this.sorttype.getValue());
+		out.writeDouble(timeArray.length);
+		out.writeLongArray(timeArray);
+		out.writeString(this.isNotEditable ? "true" : "false");
+	}
+
+    // needed to create a parcel object
+	public static final Parcelable.Creator<LogFilter> CREATOR = new Parcelable.Creator<LogFilter>() {
+		public LogFilter createFromParcel(Parcel in) {
+			return new LogFilter(in);
+		}
+
+		public LogFilter[] newArray(int size) {
+			return new LogFilter[size];
+		}
+	};
+
+	/** constructor
+     * that takes a (filter) Parcel and gives you an LogFilter populated
+	 * with it's values.
+     * @param in {@link Parcel parcel}
+     * */
+	private LogFilter(Parcel in) {
+		HashMap<String, ArrayList<String>> values = new HashMap<String, ArrayList<String>>();
+		in.readMap(values, ArrayList.class.getClassLoader());
+
+		this.BSSIDs = values.get(BSSID_KEY);
+		this.ESSIDs = values.get(ESSID_KEY);
+		this.protocols = values.get(protocols);
+
+		if (this.BSSIDs == null)
+			this.BSSIDs = new ArrayList<String>();
+		if (this.ESSIDs == null)
+			this.ESSIDs = new ArrayList<String>();
+		if (this.protocols == null)
+			this.protocols = new ArrayList<String>();
+
+		this.sorttype = SortType.values()[Math.min(in.readInt(), SortType.values().length)];
+
+		int size = (int) in.readDouble();
+		long timeArray[] = new long[size];
+		in.readLongArray(timeArray);
+
+		this.belowTimestamp = timeArray[1];
+		this.aboveTimestamp = timeArray[0];
+
+		String bool = in.readString();
+		if (bool.equals("true"))
+			this.isNotEditable = true;
+	}
+
+    /**
+     * If the filter can be edited this method returns false.
+     * @return boolean
+     */
+	public boolean isNotEditable() {
+		return this.isNotEditable;
+	}
+
+    /**
+     * Returns the filter's sorttype
+     * @return {@link de.tudarmstadt.informatik.hostage.ui2.model.LogFilter.SortType, sorttype}
+     */
+	public SortType getSorttype() {
+		return this.sorttype;
+	}
+
+    /**
+     * Returns the filtered essid names.
+     * @return ArrayList<String>
+     */
+	public ArrayList<String> getBSSIDs() {
+		return this.BSSIDs;
+	}
+    /**
+     * Returns the filtered bssid names.
+     * @return ArrayList<String>
+     */
+	public ArrayList<String> getESSIDs() {
+		return this.ESSIDs;
+	}
+    /**
+     * Returns the filtered protocol names.
+     * @return ArrayList<String>
+     */
+	public ArrayList<String> getProtocols() {
+		return this.protocols;
+	}
+
+    /**
+     * If you don't want a filter to be editable, call this method and insert true
+     * @param b boolean
+     */
+	public void setIsNotEditable(boolean b) {
+		this.isNotEditable = b;
+	}
+
+    /**
+     * Returns the filtered maximal timestamp a entry could have.
+     * The default is max long.
+     * @return long timestamp
+     */
+	public long getBelowTimestamp() {
+		return this.belowTimestamp;
+	}
+    /**
+     * Returns the filtered minimal timestamp a entry could have.
+     * The default is min long.
+     * @return long timestamp
+     */
+	public long getAboveTimestamp() {
+		return this.aboveTimestamp;
+	}
+
+    /**
+     * Set the protocols which a {@link de.tudarmstadt.informatik.hostage.logging.Record Record} can have.
+     * @param protocols ArrayList<String>
+     */
+	public void setProtocols(ArrayList<String> protocols) {
+		this.protocols = protocols;
+	}
+
+    /**
+     * Set the bssids which a {@link de.tudarmstadt.informatik.hostage.logging.Record Record} can have.
+     * @param bssids ArrayList<String>
+     */
+	public void setBSSIDs(ArrayList<String> bssids) {
+		this.BSSIDs = bssids;
+	}
+
+    /**
+     * Set the Essids which a {@link de.tudarmstadt.informatik.hostage.logging.Record Record} can have.
+     * @param essids ArrayList<String>
+     */
+	public void setESSIDs(ArrayList<String> essids) {
+		this.ESSIDs = essids;
+	}
+
+    /**
+     * Set the minimal Timestamp a filter {@link de.tudarmstadt.informatik.hostage.logging.Record Record} can have.
+     * @param timestamp long
+     */
+	public void setAboveTimestamp(long timestamp) {
+		this.aboveTimestamp = timestamp;
+	}
+
+    /**
+     * Set the maximal Timestamp a filtered {@link de.tudarmstadt.informatik.hostage.logging.Record Record} can have.
+     * @param timestamp long
+     */
+	public void setBelowTimestamp(long timestamp) {
+		this.belowTimestamp = timestamp;
+	}
+
+    /**
+     * Set the {@link SortType SortType}.
+     * @param type SortType
+     */
+	public void setSorttype(SortType type) {
+		this.sorttype = type;
+	}
+
+    /**
+     * Returns the query statement string for all filtered BSSIDs.
+     * This method is used to perform a sql query.
+     * @param tablename String, the table name.
+     * @param key String, the table column name.
+     * @return queryString String
+     */
+	public String getBSSIDQueryStatement(String tablename, String key) {
+		return this.convertArrayListToQueryString(this.BSSIDs, tablename, key);
+	}
+
+    /**
+     * Returns the query statement string for all filtered ESSIDs.
+     * This method is used to perform a sql query.
+     * @param tablename String, the table name.
+     * @param key String, the table column name.
+     * @return queryString String
+     */
+	public String getESSIDQueryStatement(String tablename, String key) {
+		return this.convertArrayListToQueryString(this.ESSIDs, tablename, key);
+	}
+
+    /**
+     * Returns the query statement string for all filtered protocols.
+     * This method is used to perform a sql query.
+     * @param tablename String, the table name.
+     * @param key String, the table column name.
+     * @return queryString String
+     */
+	public String getProtocolsQueryStatement(String tablename, String key) {
+		return this.convertArrayListToQueryString(this.protocols, tablename, key);
+	}
+
+    /**
+     * Returns true if the filter has any attributes set.
+     * @return boolean
+     */
+	public boolean isSet() {
+		boolean hasTime = this.hasATimestamp();
+		boolean hasBSSIDs = this.hasBSSIDs();
+		boolean hasESSIDs = this.hasESSIDs();
+		boolean hasProtocols = this.hasProtocols();
+
+		return hasBSSIDs || hasESSIDs || hasProtocols | hasTime;
+	}
+
+    /**
+     * Returns true if the filter has more than one bssid.
+     * @return boolean
+     */
+	public boolean hasBSSIDs() {
+		return this.getBSSIDs().size() > 0;
+	}
+    /**
+     * Returns true if the filter has more than one essid.
+     * @return boolean
+     */
+	public boolean hasESSIDs() {
+		return this.getESSIDs().size() > 0;
+	}
+    /**
+     * Returns true if the filter has more than one protocl.
+     * @return boolean
+     */
+	public boolean hasProtocols() {
+		return this.getProtocols().size() > 0;
+	}
+
+    /**
+     * Returns true if the filter has a minimal timestamp.
+     * @return boolean
+     */
+	public boolean hasAboveTimestamp() {
+		return this.aboveTimestamp != Long.MIN_VALUE;
+	}
+    /**
+     * Returns true if the filter has a maximal timestamp.
+     * @return boolean
+     */
+	public boolean hasBelowTimestamp() {
+		return this.belowTimestamp != Long.MAX_VALUE;
+	}
+    /**
+     * Returns true if the filter has a any timestamp.
+     * @return boolean
+     */
+	public boolean hasATimestamp() {
+		return this.hasBelowTimestamp() || this.hasAboveTimestamp();
+	}
+
+    /**
+     * Returns a query statement to perform a sql query. The given list will be concatenate by an OR statement.
+     * @param list ArrayList<String> The entries which should be concatenate.
+     * @param table The table name.
+     * @param key The table column name.
+     * @return queryString string
+     */
+	public String convertArrayListToQueryString(ArrayList<String> list, String table, String key) {
+		String statement = "";
+		if (list == null)
+			return statement;
+		statement = " ( ";
+
+		int i = 0, max = list.size();
+		for (String element : list) {
+			i++;
+			statement = statement + table + "." + key + " = " + "'" + element + "'";
+			if (i == max)
+				continue;
+			statement = statement + " OR ";
+		}
+		statement = statement + " ) ";
+
+		return statement;
+	}
+
+}

+ 49 - 0
src/de/tudarmstadt/informatik/hostage/ui/model/PlotComparisonItem.java

@@ -0,0 +1,49 @@
+package de.tudarmstadt.informatik.hostage.ui2.model;
+
+import java.util.ArrayList;
+
+/**
+ * Created by Julien on 16.02.14.
+ */
+public class PlotComparisonItem{
+
+    private Double value1;
+    private Double value2;
+
+    private String title;
+
+    private Integer color = 0;
+
+    private ArrayList<PlotComparisonItem> childItems;
+
+    /*CONSTRUCTOR*/
+    public PlotComparisonItem(String title, Integer color , Double value1, Double value2){
+        super();
+        this.color = color;
+        this.title = title;
+        this.value1 = value1;
+        this.value2 = value2;
+    }
+
+    public ArrayList<PlotComparisonItem> getChildItems(){
+        return this.childItems;
+    }
+    public void setChildItems(ArrayList<PlotComparisonItem> other){
+        this.childItems = other;
+    }
+    public String getTitle(){
+        return this.title;
+    }
+    public Double getValue1(){
+        return this.value1;
+    }
+    public Double getValue2(){
+        return this.value2;
+    }
+    public void setColor(Integer color){
+        this.color = color;
+    }
+    public Integer getColor(){
+        return this.color;
+    }
+}

+ 24 - 0
src/de/tudarmstadt/informatik/hostage/ui/model/ServicesListItem.java

@@ -0,0 +1,24 @@
+package de.tudarmstadt.informatik.hostage.ui2.model;
+
+/**
+ * @author Daniel Lazar
+ * @created 06.02.14
+ *
+ * defines a service list item
+ */
+public class ServicesListItem {
+	public String protocol;
+	public int attacks;
+
+	public boolean activated;
+
+    /**
+     * constructor of a service list item
+     *
+     * @param protocol protocol of this item, e.g. ftp
+     */
+	public ServicesListItem(String protocol){
+		this.protocol = protocol;
+		this.activated = false;
+	}
+}

+ 200 - 0
src/de/tudarmstadt/informatik/hostage/ui/popup/AbstractPopup.java

@@ -0,0 +1,200 @@
+package de.tudarmstadt.informatik.hostage.ui2.popup;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Rect;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.LinearLayout;
+import android.widget.PopupWindow;
+
+import de.tudarmstadt.informatik.hostage.R;
+
+/**
+ * Created by Julien on 13.02.14.
+ */
+public abstract class AbstractPopup {
+
+    //static final int ORIENTATION_LANDSCAPE = 2;
+
+    /**
+     * OnPopupItemClickListener
+     * The listener will be called if the user selects a table row
+     */
+    public interface OnPopupItemClickListener {
+        /**
+         * Will be called if the user tapped on an item.
+         * @param data Object
+         */
+        public void onItemClick(Object data);
+    }
+
+    private PopupWindow popupWindow;
+    private Activity context;
+    private OnPopupItemClickListener onPopupItemClickListener;
+    private LinearLayout rootView;
+    private LayoutInflater lInf;
+	private View lastItemView;
+
+    /**
+     * Override to return the layout id.
+     * @return int layoutID
+     */
+    abstract public int getLayoutId();
+
+    /**
+     * Override to make additional stuff with the rootview.
+     * @param view rootview
+     */
+    abstract void configureView(View view);
+
+    /**
+     * Constructor
+     * @param context Context
+     * @param  listener OnPopupItemClickListener
+     */
+    public AbstractPopup(Context context, OnPopupItemClickListener listener) {
+        super();
+        this.context = (Activity) context;
+        this.onPopupItemClickListener = listener;
+        this.popupWindow = new PopupWindow(context);
+        this.popupWindow.setOutsideTouchable(true);
+        this.popupWindow.setFocusable(true);
+        this.lInf = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+    }
+
+    /**
+     * Override to return a linear layout to add a scrollview.
+     * @return LinearLayout
+     */
+    public abstract LinearLayout getScrollableItemLayout();
+
+    /**
+     * Returns the root view
+     * @return View the rootview
+     */
+    public View getRootView(){
+        return this.rootView;
+    }
+
+    /**
+     * Adds a table row item.
+     * @param item {@link de.tudarmstadt.informatik.hostage.ui2.popup.AbstractPopupItem AbstractPopupItem}
+     */
+    public void addItem(final AbstractPopupItem item)	{
+        View view = item.getRootView();
+
+        if (this.rootView == null){
+            this.rootView = (LinearLayout) this.lInf.inflate(this.getLayoutId(), null);
+            this.configureView(this.rootView);
+        }
+        if (this.rootView != null){
+            this.getScrollableItemLayout().addView(view);
+	        lastItemView = view;
+
+            //this.rootView.addView(view);
+            view.setOnTouchListener(new View.OnTouchListener() {
+                @Override
+                public boolean onTouch(View view, MotionEvent event) {
+	                if(event.getAction() == MotionEvent.ACTION_DOWN){
+						item.onItemSelect(event);
+	                } else if (event.getAction() == MotionEvent.ACTION_CANCEL || event.getAction() == MotionEvent.ACTION_MOVE){
+                        item.onItemDeselect(event);
+                    } else if (event.getAction() == MotionEvent.ACTION_UP){
+                        item.onItemDeselect(event);
+                        AbstractPopup.this.onPopupItemClickListener.onItemClick(item.onClickedResult(event));
+                        AbstractPopup.this.popupWindow.dismiss();
+                    }
+                    return true;
+                }
+            });
+        }
+
+    }
+
+    /**
+     * Returns the rootview.
+     * If the root view is null, it initialises it with the layout id.
+     * @return View the root view
+     */
+    public View getPopupView(){
+        if (this.rootView == null){
+            this.rootView = (LinearLayout) this.lInf.inflate(this.getLayoutId(), null);
+        }
+        return this.rootView;
+    }
+
+    /**
+     * Opens the Popup View on top of the given anchor.
+     * @param anchorView View
+     */
+    public void showOnView(final View anchorView)	{
+        if (this.rootView == null){
+            this.rootView = (LinearLayout) this.lInf.inflate(this.getLayoutId(), null);
+        }
+        if (this.rootView != null){
+            AbstractPopup.this.popupWindow.dismiss();
+
+            this.popupWindow.setContentView(this.rootView);
+
+            final Rect windowFrame= new Rect();
+
+            Window window = this.context.getWindow();
+            window.getDecorView().getWindowVisibleDisplayFrame(windowFrame);
+            //int orientation = this.context.getResources().getConfiguration().orientation;
+            int windowWidth = windowFrame.width();
+            int windowHeight = windowFrame.height();
+
+            final int[] position = new int[2];
+            anchorView.getLocationOnScreen(position);
+            final int anchorWidth = anchorView.getWidth();
+
+            this.rootView.measure(WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT);
+            int width = this.rootView.getMeasuredWidth();
+            int height = this.rootView.getMeasuredHeight();
+
+            //int alh = (position[0] + width) - windowFrame.width();
+            //if (alh < 0) alh = 0;
+            int offset = windowFrame.top;
+
+            int x = position[0] + (anchorWidth / 2) - (width / 2);
+            int y = (position[1] - height) + offset;
+
+            height+=(offset/2);
+
+            width = windowWidth < width ? windowWidth : width;
+
+            x = Math.max(0, x);
+            x = Math.min(windowWidth - width, x);
+
+            height = (windowHeight < height ? windowHeight : height) - 10;
+
+            y = Math.max(0, y);
+            y = Math.min(windowHeight - height, y);
+
+            AbstractPopup.this.configureView(this.rootView);
+
+            int smallBottomOffset = 45;
+            this.popupWindow.setWidth(width);
+            this.popupWindow.setHeight(height);
+
+	        if(lastItemView != null){
+		        View v = lastItemView.findViewById(R.id.bottom_seperator);
+
+		        if(v != null){
+			        v.setVisibility(View.GONE);
+		        }
+	        }
+
+            this.popupWindow.showAtLocation(anchorView, Gravity.NO_GRAVITY, x, y-smallBottomOffset);
+
+        }
+    }
+
+
+}

+ 133 - 0
src/de/tudarmstadt/informatik/hostage/ui/popup/AbstractPopupItem.java

@@ -0,0 +1,133 @@
+package de.tudarmstadt.informatik.hostage.ui2.popup;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+
+import java.util.HashMap;
+
+/**
+ * Created by Julien on 13.02.14.
+ */
+public abstract class AbstractPopupItem {
+    private int itemId;
+    private String title;
+
+    private View rootView;
+
+    private LayoutInflater lInf;
+
+    public HashMap<Object, Object> data;
+
+    /**
+     * Override to return the layout id.
+     * @return int layoutID
+     */
+    abstract public int getLayoutId();
+
+    /**
+     * Override to do additional stuff with the rootview.
+     *
+     * @param  view the root view
+     */
+    abstract public void configureItemView(View view);
+
+    /**
+     * Set different types of data. Calls {@link #configureItemView(android.view.View)}
+     * @param key String
+     * @param value Object
+     */
+    public void setValue(String key, Object value){
+        if (key != null && value != null){
+            this.data.put(key, value);
+            if (this.rootView != null) this.configureItemView(this.rootView);
+        }
+    }
+
+    /**
+     * Add other data to the item.
+     * @param map HashMap<Object, Object> optional data.
+     */
+    public void setMultipleData(HashMap<Object, Object> map){
+        if (map != null){
+            for(Object key : map.keySet()){
+                this.data.put(key, map.get(key));
+            }
+            if (this.rootView != null) this.configureItemView(this.rootView);
+        }
+    }
+
+    public void setTitle(String title){
+        this.title = title;
+        if (this.rootView != null) this.configureItemView(this.rootView);
+    }
+    public String getTitle(){
+        return this.title;
+    }
+
+    /**
+     * Set a specific item ID to identify it.
+     * @param  id int
+     */
+    public void setItemId(int id){
+        this.itemId = id;
+        if (this.rootView != null) this.configureItemView(this.rootView);
+    }
+
+    /**
+     * Returns the item ID.
+     * @return int ID
+     */
+    public int getItemId() {
+        return this.itemId;
+    }
+
+    /**
+     * Constructor
+     * @param  context Context
+     */
+    public AbstractPopupItem(Context context) {
+        super();
+        this.lInf = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        this.data = new HashMap<Object, Object>();
+    }
+
+    /**
+     * Returns the rootview.
+     * This method calls everytime the ConfigureItemView methode.
+     * @return View rootview
+     */
+    public View getRootView(){
+        if (this.rootView == null){
+            this.rootView = this.lInf.inflate(this.getLayoutId(), null);
+        }
+        this.configureItemView(this.rootView);
+
+        return this.rootView;
+    }
+
+    /**
+     * The method is called if the user clicks the rootview.
+     * @param   event MotionEvent
+     * @return Object object
+     */
+    public Object onClickedResult(MotionEvent event){
+        return this;
+    }
+
+    /**
+     * Will be called if the user selected the view.
+     * @param  event MotionEvent
+     */
+	public void onItemSelect(MotionEvent event){
+	}
+
+    /**
+     * Will be called if the user deselects the view.
+     * @param  event MotionEvent
+     */
+	public void onItemDeselect(MotionEvent event){
+
+	}
+}

+ 86 - 0
src/de/tudarmstadt/informatik/hostage/ui/popup/SimplePopupItem.java

@@ -0,0 +1,86 @@
+package de.tudarmstadt.informatik.hostage.ui2.popup;
+
+import android.content.Context;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.RadioButton;
+import android.widget.TextView;
+
+import de.tudarmstadt.informatik.hostage.R;
+
+/**
+ * Created by Julien on 13.02.14.
+ */
+public class SimplePopupItem extends AbstractPopupItem {
+
+    public boolean selected;
+	private Context context;
+	private View container;
+
+    /**
+     * Constructor
+     * @param context the context
+     */
+	public SimplePopupItem(Context context) {
+        super(context);
+
+	    this.context = context;
+    }
+
+    @Override
+    public int getLayoutId(){
+        return R.layout.simple_popup_item;
+    }
+
+    @Override
+    public void configureItemView(View view){
+        TextView titleView = (TextView) view.findViewById(R.id.title_text_view);
+        RadioButton cbox = (RadioButton) view.findViewById(R.id.isSelectedButton);
+        titleView.setText(this.getTitle());
+
+        if (this.isSelected()){
+            cbox.setVisibility(View.VISIBLE);
+        } else {
+            cbox.setVisibility(View.INVISIBLE);
+        }
+    }
+
+    /**
+     * Set the selection state.
+     * @param selected boolean
+     */
+    public void setSelected(boolean selected){
+        this.selected = selected;
+        if (this.getRootView() != null) this.configureItemView(this.getRootView());
+    }
+
+    /**
+     * Return the background view.
+     * @return view the background view
+     */
+	private View getContainer(){
+		if(container == null){
+			container = this.getRootView().findViewById(R.id.popup_item_container);
+		}
+
+		return container;
+	}
+
+    /**
+     * Returns true if the item is selected, otherwise false.
+     * @return boolean
+     */
+    public boolean isSelected(){
+        return this.selected;
+    }
+
+    @Override
+	public void onItemSelect(MotionEvent event){
+		getContainer().setBackgroundColor(
+				context.getResources().getColor(android.R.color.holo_blue_light));
+	}
+    @Override
+	public void onItemDeselect(MotionEvent event){
+		getContainer().setBackgroundColor(context.getResources().getColor(android.R.color.transparent));
+	}
+}

+ 58 - 0
src/de/tudarmstadt/informatik/hostage/ui/popup/SimplePopupTable.java

@@ -0,0 +1,58 @@
+package de.tudarmstadt.informatik.hostage.ui2.popup;
+
+import android.content.Context;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import de.tudarmstadt.informatik.hostage.R;
+
+/**
+ * Created by Julien on 13.02.14.
+ */
+public class SimplePopupTable extends AbstractPopup {
+
+    private String title;
+
+    /**
+     * Set the popup title.
+     * @param title string
+     */
+    public void setTitle(String title){
+        this.title = title;
+        if (this.getPopupView() != null) this.configureView(this.getPopupView());
+    }
+
+    /**
+     * Returns the popup title.
+     * @return String title.
+     */
+    public String getTitle(){
+        return this.title;
+    }
+
+    /**
+     * Constructor
+     * @param context the context
+     * @param listener user event listener
+     */
+    public SimplePopupTable(Context context, OnPopupItemClickListener listener){
+        super(context, listener);
+    }
+
+    @Override
+    public LinearLayout getScrollableItemLayout() {
+        return (LinearLayout) this.getRootView().findViewById(R.id.item_scroll_layout);
+    }
+
+    @Override
+    public int getLayoutId(){
+        return R.layout.simple_popup_table;
+    }
+
+    @Override
+    void configureView(View view){
+        TextView titleView = (TextView) view.findViewById(R.id.title_text_view);
+        titleView.setText(this.title);
+    }
+}

+ 133 - 0
src/de/tudarmstadt/informatik/hostage/ui/popup/SplitPopupItem.java

@@ -0,0 +1,133 @@
+package de.tudarmstadt.informatik.hostage.ui2.popup;
+
+import android.content.Context;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.TextView;
+
+import de.tudarmstadt.informatik.hostage.R;
+
+/**
+ * Created by Julien on 16.02.14.
+ */
+public class SplitPopupItem extends AbstractPopupItem {
+
+    public final static String LEFT_TITLE = "LEFT_TITLE";
+    public final static String RIGHT_TITLE = "RIGHT_TITLE";
+    public final static String LEFT_SUBTITLE = "LEFT_SUBTITLE";
+    public final static String RIGHT_SUBTITLE = "RIGHT_SUBTITLE";
+
+    public boolean wasRightTouch;
+
+	private Context context;
+	private View left_container;
+	private View right_container;
+
+    /**
+     * Constructor
+     *
+     * @param  context Context
+     */
+    public SplitPopupItem(Context context){
+        super(context);
+
+	    this.context = context;
+    }
+
+    @Override
+    public int getLayoutId(){
+        return R.layout.split_popup_item;
+    }
+
+    @Override
+    public void configureItemView(View view){
+        String leftTitle = (String) this.data.get(LEFT_TITLE);
+        String rightTitle = (String) this.data.get(RIGHT_TITLE);
+
+        String leftSubtitle = (String) this.data.get(LEFT_SUBTITLE);
+        String rightSubtitle = (String) this.data.get(RIGHT_SUBTITLE);
+
+        TextView leftTitleView = (TextView)view.findViewById(R.id.left_title_text_view);
+        leftTitleView.setText(leftTitle);
+        TextView leftSubtitleView = (TextView)view.findViewById(R.id.left_subtitle_text_view);
+        if (leftSubtitle != null){
+            leftSubtitleView.setText(leftSubtitle);
+        } else {
+            leftSubtitleView.setText("-");
+        }
+
+        TextView rightTitleView = (TextView)view.findViewById(R.id.right_title_text_view);
+        rightTitleView.setText(rightTitle);
+        TextView rightSubtilteView = (TextView)view.findViewById(R.id.right_subtitle_text_view);
+        if (rightSubtitle != null){
+            rightSubtilteView.setText(rightSubtitle);
+        } else {
+            rightSubtilteView.setText("-");
+        }
+    }
+
+    /**
+     * Returns the displayed object for the clicked position in the view.
+     * E.g. the user tapped the right side, it returns the object representing the right side of the clickt view.
+     * @param event MotionEvent
+     * @return Object
+     */
+    public Object onClickedResult(MotionEvent event){
+        this.wasRightTouch = isRightTouch(event);
+        return this;
+    }
+
+    /**
+     * Returns true if the user touched the right side of the view.
+     * @return boolean isRightTouch
+     */
+	private boolean isRightTouch(MotionEvent event){
+		return event.getX() > this.getRootView().getX() + (this.getRootView().getWidth() / 2);
+	}
+
+    /**
+     * Returns the left view.
+     * @return View the left view
+     */
+	private View getLeftContainer(){
+		if(left_container == null){
+			left_container = this.getRootView().findViewById(R.id.popup_left_container);
+		}
+
+		return left_container;
+	}
+
+    /**
+     * Returns the right view.
+     * @return View the right view
+     */
+	private View getRightContainer(){
+		if(right_container == null){
+			right_container = this.getRootView().findViewById(R.id.popup_right_container);
+		}
+
+		return right_container;
+	}
+
+    @Override
+	public void onItemSelect(MotionEvent event){
+		int blue_color = context.getResources().getColor(android.R.color.holo_blue_light);
+		int trans_color = context.getResources().getColor(android.R.color.transparent);
+
+		if(!isRightTouch(event)){
+			getLeftContainer().setBackgroundColor(blue_color);
+			getRightContainer().setBackgroundColor(trans_color);
+		} else {
+			getLeftContainer().setBackgroundColor(trans_color);
+			getRightContainer().setBackgroundColor(blue_color);
+		}
+	}
+
+    @Override
+	public void onItemDeselect(MotionEvent event){
+		int trans_color = context.getResources().getColor(android.R.color.transparent);
+
+		getLeftContainer().setBackgroundColor(trans_color);
+		getRightContainer().setBackgroundColor(trans_color);
+	}
+}

+ 52 - 0
src/de/tudarmstadt/informatik/hostage/ui/swipelist/SwipeListView.java

@@ -0,0 +1,52 @@
+package de.tudarmstadt.informatik.hostage.ui2.swipelist;
+
+import android.content.Context;
+import android.util.AttributeSet;
+
+/**
+ * Extends the SwipeListView with an mechanism to allow to open only one item at the same time.
+ *
+ * @author Alexander Brakowski
+ * @created 28.02.14 22:05
+ */
+public class SwipeListView extends com.fortysevendeg.android.swipelistview.SwipeListView {
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public SwipeListView(Context context, int swipeBackView, int swipeFrontView) {
+		super(context, swipeBackView, swipeFrontView);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public SwipeListView(Context context, AttributeSet attrs) {
+		super(context, attrs);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public SwipeListView(Context context, AttributeSet attrs, int defStyle) {
+		super(context, attrs, defStyle);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	protected void onOpened(int position, boolean toRight) {
+		super.onOpened(position, toRight);
+
+		int start = getFirstVisiblePosition();
+		int end = getLastVisiblePosition();
+
+		// close all visible items other then the current one
+		for(int i=start; i<=end; i++){
+			if(i != position){
+				closeAnimate(i);
+			}
+		}
+	}
+}