Browse Source

switched profiles persistence to json; stated working on profile manager swipe tip

Alexander Brakowski 10 years ago
parent
commit
aadc371569

+ 1 - 1
AndroidManifest.xml

@@ -32,7 +32,7 @@
         android:vmSafeMode="true" >
         <meta-data
             android:name="com.google.android.gms.version"
-            android:value="@integer/google_play_services_version" />
+            android:value="14" />
         <meta-data
             android:name="com.google.android.maps.v2.API_KEY"
             android:value="AIzaSyCqh4bb4aMzvDcpDfiqHyXoAWFTQ6iNxe8" />

+ 15 - 7
res/layout/profile_manager_list_item.xml

@@ -1,8 +1,14 @@
 <?xml version="1.0" encoding="utf-8"?>
 
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:layout_width="wrap_content"
-              android:layout_height="wrap_content">
+	<FrameLayout
+			xmlns:android="http://schemas.android.com/apk/res/android"
+			  android:layout_width="wrap_content"
+              android:layout_height="wrap_content"
+              android:layout_alignParentLeft="true"
+              android:layout_marginLeft="0dp"
+              android:layout_alignParentTop="true"
+              android:layout_marginTop="0dp"
+			>
 
 	<RelativeLayout
         android:id="@+id/swipelist_backview"
@@ -55,7 +61,7 @@
 	<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 	                android:id="@+id/swipelist_frontview"
 	                android:layout_width="match_parent"
-	                android:layout_height="wrap_content"
+	                android:layout_height="match_parent"
 	                android:padding="5dp"
 	                android:baselineAligned="false"
 	                android:background="@drawable/panel_bg_selector">
@@ -117,13 +123,12 @@
 				android:orientation="horizontal"
 				android:layout_width="fill_parent"
 				android:layout_height="fill_parent"
-				android:layout_alignParentBottom="true"
 				android:layout_below="@+id/profile_manager_item_text"
 				android:padding="10dp"
 				f:horizontalSpacing="10dip"
 				f:verticalSpacing="10dip"
 				android:layout_alignParentRight="true"
-				android:layout_alignParentEnd="true"
+				android:layout_alignParentEnd="false"
 				android:id="@+id/badges_container">
 			<TextView
 					android:layout_width="wrap_content"
@@ -163,5 +168,8 @@
 			          android:textAppearance="?android:attr/textAppearanceSmall" android:text="HTTP" android:id="@+id/textView7" android:layout_gravity="center_vertical"
 			          android:layout_marginLeft="10dp"/>
 		</de.tudarmstadt.informatik.hostage.ui2.layouts.FlowLayout>
+
 	</RelativeLayout>
-</FrameLayout>
+
+
+	</FrameLayout>

+ 36 - 0
res/layout/profile_manager_list_item_help.xml

@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:id="@+id/swipelist_frontview"
+              android:background="@color/bright_grey"
+              android:padding="10dp">
+
+	<TextView
+			android:layout_width="wrap_content"
+			android:layout_height="wrap_content"
+			android:textAppearance="?android:attr/textAppearanceSmall"
+			android:text="Swipe from the left or right on an item to expose all available actions for an item"
+			android:id="@+id/textView"
+			android:layout_alignParentTop="true"
+			android:layout_toRightOf="@+id/imageView"
+			android:layout_marginLeft="10dp"/>
+
+	<ImageView
+			android:layout_width="wrap_content"
+			android:layout_height="wrap_content"
+			android:id="@+id/imageView"
+			android:src="@drawable/swipe_icon"
+			android:layout_alignParentTop="true"
+			android:layout_alignParentLeft="true"
+			android:layout_alignParentStart="true"
+			android:layout_alignBottom="@+id/textView"/>
+
+	<FrameLayout
+			android:layout_width="wrap_content"
+			android:layout_height="wrap_content"
+			android:id="@+id/swipelist_backview">
+	</FrameLayout>
+</RelativeLayout>

+ 1 - 1
res/values/strings.xml

@@ -22,7 +22,7 @@
     <string name="information">Information</string>
 	<string name="wifi_not_connected_msg">You are not connected to a WiFi network. \n\nPlease connect to one, before trying to activate HosTaGe.</string>
 	<string name="no_network_connection_threatmap_msg">Currently you are not connected to the Internet.\n\nPlease establish a connection to use the Threatmap.</string>
-	<string name="profile_no_services_msg">The current active protocol does not seem to monitor any services.\n\nPlease activate some services to monitor in the profile.</string>
+	<string name="profile_no_services_msg">The current active profile does not seem to monitor any services.\n\nPlease activate some services to monitor in the profile.</string>
 
     <string name="monitor_current_connection">Monitor current connection</string>
     <string name="active_profile">Active profile: </string>

+ 25 - 11
src/de/tudarmstadt/informatik/hostage/Hostage.java

@@ -5,6 +5,7 @@ import java.io.InputStreamReader;
 import java.net.Socket;
 import java.security.SecureRandom;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
 
@@ -55,6 +56,8 @@ import de.tudarmstadt.informatik.hostage.ui2.activity.MainActivity;
  */
 public class Hostage extends Service {
 
+	private HashMap<String, Boolean> mProtocolActiveAttacks;
+
 	public class LocalBinder extends Binder {
 		public Hostage getService() {
 			return Hostage.this;
@@ -207,15 +210,6 @@ public class Hostage extends Service {
 		return 0;
 	}
 
-	public boolean hasActiveAttacks() {
-		for (Listener listener : listeners) {
-			if (listener.getHandlerCount() > 0) {
-				return true;
-			}
-		}
-		return false;
-	}
-
 	/**
 	 * Determines if there any listener is currently running.
 	 * 
@@ -272,8 +266,9 @@ public class Hostage extends Service {
 	public void notifyUI(String sender, String[] values) {
 		createNotification();
 		// Send Notification
-		if (sender.equals(Handler.class.getName()) && values[0].equals(R.string.broadcast_started)) {
-			attackNotification();
+		if (sender.equals(Handler.class.getName()) && values[0].equals(getString(R.string.broadcast_started))) {
+			this.mProtocolActiveAttacks.put(values[1], true);
+			//attackNotification();
 		}
 		// Inform UI of Preference Change
 		Intent intent = new Intent(getString(R.string.broadcast));
@@ -295,6 +290,9 @@ public class Hostage extends Service {
 		implementedProtocols = getImplementedProtocols();
 		connectionInfo = getSharedPreferences(getString(R.string.connection_info), Context.MODE_PRIVATE);
 		connectionInfoEditor = connectionInfo.edit();
+
+		mProtocolActiveAttacks = new HashMap<String, Boolean>();
+
 		createNotification();
 		registerNetReceiver();
 		updateConnectionInfo();
@@ -402,6 +400,7 @@ public class Hostage extends Service {
 			if (listener.getProtocolName().equals(protocolName) && listener.getPort() == port) {
 				if (listener.isRunning()) {
 					listener.stop();
+					mProtocolActiveAttacks.remove(protocolName);
 				}
 			}
 		}
@@ -416,6 +415,7 @@ public class Hostage extends Service {
 		for (Listener listener : listeners) {
 			if (listener.isRunning()) {
 				listener.stop();
+				mProtocolActiveAttacks.remove(listener.getProtocolName());
 			}
 		}
 		// Toast.makeText(getApplicationContext(), "SERVICES STOPPED!",
@@ -596,6 +596,18 @@ public class Hostage extends Service {
 		unregisterReceiver(netReceiver);
 	}
 
+	public boolean hasProtocolActiveAttacks(String protocol){
+		if(!mProtocolActiveAttacks.containsKey(protocol)) return false;
+		return mProtocolActiveAttacks.get(protocol);
+	}
+
+	public boolean hasActiveAttacks(){
+		for(boolean b: mProtocolActiveAttacks.values()){
+			if(b) return true;
+		}
+
+		return false;
+	}
 	/**
 	 * Updates the connection info and saves them in the the SharedPreferences
 	 * for session data.
@@ -613,6 +625,8 @@ public class Hostage extends Service {
 		editor.commit();
 		SetExternalIPTask async = new SetExternalIPTask();
 		async.execute(new String[] { "http://ip2country.sourceforge.net/ip2c.php?format=JSON" });
+
+		this.mProtocolActiveAttacks.clear();
 	}
 
 }

+ 12 - 0
src/de/tudarmstadt/informatik/hostage/model/JSONSerializable.java

@@ -0,0 +1,12 @@
+package de.tudarmstadt.informatik.hostage.model;
+
+import org.json.JSONObject;
+
+/**
+ * @author Alexander Brakowski
+ * @created 23.03.14 11:45
+ */
+public interface JSONSerializable<T> {
+	public T fromJSON(JSONObject json);
+	public JSONObject toJSON();
+}

+ 57 - 5
src/de/tudarmstadt/informatik/hostage/model/Profile.java

@@ -1,5 +1,8 @@
 package de.tudarmstadt.informatik.hostage.model;
 
+import org.json.JSONException;
+import org.json.JSONObject;
+
 import android.content.Context;
 import android.content.SharedPreferences;
 import android.graphics.Bitmap;
@@ -12,6 +15,7 @@ import android.os.Parcelable;
 
 import java.io.Serializable;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
@@ -22,9 +26,7 @@ import de.tudarmstadt.informatik.hostage.ui2.activity.MainActivity;
  * @author Alexander Brakowski
  * @created 14.01.14 18:04
  */
-public class Profile implements Serializable {
-	private static final long serialVersionUID = 8L;
-
+public class Profile implements JSONSerializable<Profile> {
 	public String mText;
 	public String mLabel;
 	public int mId;
@@ -32,16 +34,15 @@ public class Profile implements Serializable {
 	transient public Bitmap mIcon;
 	transient public int mIconId;
 	public String mIconName;
-
 	public String mIconPath;
 
-	public boolean mIsBackVisible = false;
 	public boolean mEditable = false;
 	public boolean mIsRandom = false;
 
 	public HashMap<String, Boolean> mActiveProtocols = new HashMap<String, Boolean>();
 	public String mGhostPorts = "";
 	public boolean mGhostActive = false;
+	public boolean mShowTooltip = false;
 
 	public Profile(){
 		this.mEditable = true;
@@ -158,4 +159,55 @@ public class Profile implements Serializable {
 
 		return ports;
 	}
+
+	public JSONObject toJSON(){
+		JSONObject jsonObj = new JSONObject();
+
+		try {
+			jsonObj.put("text", mText);
+			jsonObj.put("label", mLabel);
+			jsonObj.put("id", mId);
+			jsonObj.put("activated", mActivated);
+			jsonObj.put("icon_name", mIconName);
+			jsonObj.put("icon_path", mIconPath);
+			jsonObj.put("editable", mEditable);
+			jsonObj.put("random", mIsRandom);
+			jsonObj.put("ghost_active", mGhostActive);
+			jsonObj.put("ghost_ports", mGhostPorts);
+			jsonObj.put("active_protocols", new JSONObject(mActiveProtocols));
+		} catch (JSONException e) {
+			e.printStackTrace();
+		}
+
+		return jsonObj;
+	}
+
+	public Profile fromJSON(JSONObject json){
+		mText = json.optString("text", "");
+		mLabel = json.optString("label", "");
+		mId = json.optInt("id", -1);
+		mActivated = json.optBoolean("activated", false);
+		mIconName = json.optString("icon_name", null);
+		mIconPath = json.optString("icon_path", null);
+		mEditable = json.optBoolean("editable", true);
+		mIsRandom = json.optBoolean("random", false);
+		mGhostActive = json.optBoolean("ghost_active", false);
+		mGhostPorts = json.optString("ghost_ports", "");
+
+		JSONObject activeProtocols = json.optJSONObject("active_protocols");
+		if(activeProtocols != null){
+			Iterator keys = activeProtocols.keys();
+
+			while(keys.hasNext()){
+				String protocol = (String) keys.next();
+				try {
+					mActiveProtocols.put(protocol, activeProtocols.getBoolean(protocol));
+				} catch (JSONException e) {
+					e.printStackTrace();
+				}
+			}
+		}
+
+		return this;
+	}
 }

+ 0 - 13
src/de/tudarmstadt/informatik/hostage/model/ProfilesHolder.java

@@ -1,13 +0,0 @@
-package de.tudarmstadt.informatik.hostage.model;
-
-import java.io.Serializable;
-import java.util.HashMap;
-
-/**
- * @author Alexander Brakowski
- * @created 07.03.14 00:23
- */
-public class ProfilesHolder implements Serializable {
-	public int mIncrementValue = 1;
-	public HashMap<Integer, Profile> mProfiles;
-}

+ 214 - 46
src/de/tudarmstadt/informatik/hostage/dao/ProfileManager.java → src/de/tudarmstadt/informatik/hostage/persistence/ProfileManager.java

@@ -1,4 +1,8 @@
-package de.tudarmstadt.informatik.hostage.dao;
+package de.tudarmstadt.informatik.hostage.persistence;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
 
 import android.content.Context;
 
@@ -6,8 +10,7 @@ import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
+import java.io.InputStream;
 import java.io.StreamCorruptedException;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -20,25 +23,59 @@ import java.util.Random;
 
 import de.tudarmstadt.informatik.hostage.R;
 import de.tudarmstadt.informatik.hostage.model.Profile;
-import de.tudarmstadt.informatik.hostage.model.ProfilesHolder;
 import de.tudarmstadt.informatik.hostage.ui2.activity.MainActivity;
 import de.tudarmstadt.informatik.hostage.ui2.adapter.ProfileManagerListAdapter;
 
 /**
+ * The profile manager is responsible for persisting and deleting profiles
+ *
  * @author Alexander Brakowski
  * @created 10.02.14 20:24
  */
 public class ProfileManager {
+
+	/**
+	 * The singleton instance holder
+	 */
 	private static ProfileManager INSTANCE = null;
 
+	/**
+	 * An list adapter, which the profile manager informs about data changes
+	 */
 	private ProfileManagerListAdapter mProfileListAdapter = null;
-	private Profile mCurrentActivatedProfile = null;
-	private Profile mRandomProfile = null;
 
-	private static final String PERSIST_FILENAME = "hostage_profiles.dat";
+	/**
+	 * Holds a reference to the currently active profile
+	 */
+	private Profile mCurrentActivatedProfile = null;
 
-	private ProfilesHolder holder;
+	/**
+	 * Holds a reference to the random profile
+	 */
+	private Profile mRandomProfile = null;
 
+	/**
+	 * The profiles are being serialized and persisted into this file
+	 */
+	private static final String PERSIST_FILENAME = "hostage_profiles.json";
+
+	/**
+	 * Hold the current profile id, it will be incremented each time a new profile is added.
+	 * The new profile will get the newly incremented value as an id.
+	 */
+	public int mIncrementValue = 1;
+
+	/**
+	 * Holds all the available profiles. The key in the map is the ID of the profile.
+	 */
+	public HashMap<Integer, Profile> mProfiles;
+
+	/**
+	 * Since the profile manager should only have one instance in the whole app, we are using the singleton pattern.
+	 * This method creates a new instance of the profile manager, if no instance already exists, and returns it.
+	 *
+	 * @return the singleton instance
+	 */
 	public static ProfileManager getInstance(){
 		if(INSTANCE == null){
 			INSTANCE = new ProfileManager();
@@ -51,45 +88,82 @@ public class ProfileManager {
 		return INSTANCE;
 	}
 
+	/**
+	 * A private constructor, that can/should only be called by getInstance, since we want to enforce the usage of the singleton.
+	 */
 	private ProfileManager(){
-		holder = new ProfilesHolder();
-		holder.mProfiles = new HashMap<Integer, Profile>();
+		mProfiles = new HashMap<Integer, Profile>();
+	}
+
+	/**
+	 * Reads all data from an inputstream and appends it to a string
+	 *
+	 * @param is The input stream to read the data from
+	 * @return the whole data from the input stream as an string
+	 */
+	public String readAll( final InputStream is ) {
+		if( null == is ) {
+			return "";
+		}
+
+		StringBuilder sb = new StringBuilder();
+		int rc;
+		try {
+			while( (rc = is.read()) >= 0 ){
+				sb.append( (char) rc );
+			}
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+
+		return sb.toString();
 	}
 
+
+	/**
+	 * Reads all the data of the the profiles, that were persisted and unserializes them.
+	 *
+	 * The profiles were serialized into JSON and persisted into the android private file.
+	 * See {@see ProfileManager#persistData}.
+	 */
 	public void loadData(){
 		try {
 			FileInputStream fin = MainActivity.getContext().openFileInput(PERSIST_FILENAME);
-			ObjectInputStream ois = new ObjectInputStream(fin);
-
-			Object obj = ois.readObject();
-			ois.close();
+			JSONArray arr = new JSONArray(readAll(fin));
 			fin.close();
 
-			if(obj != null && obj instanceof ProfilesHolder){
-				this.holder = (ProfilesHolder) obj;
+			for(int i=0; i<arr.length(); i++){
+				JSONObject obj = arr.getJSONObject(i);
+
+				Profile p = new Profile();
+				p.fromJSON(obj);
 
-				for(Map.Entry<Integer, Profile> entry: holder.mProfiles.entrySet()){
-					if(entry.getValue().mActivated){
-						this.mCurrentActivatedProfile = entry.getValue();
-					}
+				mProfiles.put(p.mId, p);
 
-					if(entry.getValue().mIsRandom){
-						this.mRandomProfile = entry.getValue();
-					}
+				if(p.mId > mIncrementValue){
+					mIncrementValue = p.mId;
+				}
+
+				if(p.mActivated){
+					this.mCurrentActivatedProfile = p;
+				}
+
+				if(p.mIsRandom){
+					this.mRandomProfile = p;
 				}
 			}
+
 		} catch (FileNotFoundException e) {
 			e.printStackTrace();
 		} catch (StreamCorruptedException e) {
 			e.printStackTrace();
 		} catch (IOException e) {
 			e.printStackTrace();
-		} catch (ClassNotFoundException e) {
+		} catch (JSONException e) {
 			e.printStackTrace();
 		} finally {
-			if(holder.mProfiles.size() == 0){
+			if(mProfiles.size() == 0){
 				this.fillWithDefaultData();
-				loadData();
 			}
 
 			if(this.mRandomProfile != null){
@@ -98,13 +172,19 @@ public class ProfileManager {
 		}
 	}
 
+	/**
+	 * All the profiles that are hold by the profile manager are being serialized into JSON and then written into an private android file.
+	 */
 	public void persistData(){
 		try {
 			FileOutputStream fout = MainActivity.getContext().openFileOutput(PERSIST_FILENAME, Context.MODE_PRIVATE);
-			ObjectOutputStream oos = new ObjectOutputStream(fout);
 
-			oos.writeObject(holder);
-			oos.close();
+			JSONArray arr = new JSONArray();
+			for(Profile p: mProfiles.values()){
+				arr.put(p.toJSON());
+			}
+
+			fout.write(arr.toString().getBytes());
 			fout.close();
 		} catch (FileNotFoundException e) {
 			e.printStackTrace();
@@ -114,22 +194,39 @@ public class ProfileManager {
 
 	}
 
+	/**
+	 * Retrieves all the profiles as an List
+	 * @return a list that holds all the profiles
+	 */
 	public List<Profile> getProfilesList(){
 		return new ArrayList<Profile>(getProfilesCollection());
 	}
 
+	/**
+	 * Retrieves all the profiles as an collection
+	 * @return a collection of all the profiles
+	 */
 	public Collection<Profile> getProfilesCollection(){
-		if(holder.mProfiles.size() == 0 || holder.mProfiles == null){
+		if(mProfiles.size() == 0 || mProfiles == null){
 			this.loadData();
 		}
 
-		return holder.mProfiles.values();
+		return mProfiles.values();
 	}
 
+	/**
+	 * Retrieves an map of all the profiles. The key in the map is the ID of an profile.
+	 * @return a map of profiles
+	 */
 	public Map<Integer, Profile> getMapProfiles(){
-		return holder.mProfiles;
+		return mProfiles;
 	}
 
+	/**
+	 * Activates and deactivates protocols randomly in the given profile
+	 *
+	 * @param profile the profile to randomize the protocols for
+	 */
 	public void randomizeProtocols(Profile profile){
 		LinkedList<String> protocols = new LinkedList<String>(Arrays.asList(MainActivity.getContext().getResources().getStringArray(R.array.protocols)));
 		protocols.remove("GHOST");
@@ -150,12 +247,18 @@ public class ProfileManager {
 		persistData();
 	}
 
-	public long persistProfile(Profile profile){
+	/**
+	 * Adds or updates a given profile.
+	 *
+	 * @param profile the profile to persist
+	 * @return the id the profile was assigned to
+	 */
+	public int persistProfile(Profile profile){
 		if(profile.mId == -1){
-			profile.mId = ++holder.mIncrementValue;
+			profile.mId = ++mIncrementValue;
 		}
 
-		holder.mProfiles.put(profile.mId, profile);
+		mProfiles.put(profile.mId, profile);
 
 		this.persistData();
 
@@ -166,29 +269,48 @@ public class ProfileManager {
 		return profile.mId;
 	}
 
+	/**
+	 * Retrieves the profile with the given id
+	 *
+	 * @param id the id of the profile
+	 * @return the profile
+	 */
 	public Profile getProfile(int id){
-		if(holder.mProfiles.size() == 0){
+		if(mProfiles.size() == 0){
 			loadData();
 		}
 
-		if(this.holder.mProfiles.containsKey(id)){
-			return this.holder.mProfiles.get(id);
+		if(this.mProfiles.containsKey(id)){
+			return this.mProfiles.get(id);
 		}
 
 		return null;
 	}
 
+	/**
+	 * Adds a profile
+	 *
+	 * @param profile the profile to add
+	 */
 	public void addProfile(Profile profile){
 		this.addProfile(profile, true);
 	}
 
+	/**
+	 * Adds a given profile to the profile manager.
+	 *
+	 * @param profile the profile to add
+	 * @param persist true,  if the profile should also be persisted immediatly,
+	 *                false, if the profile should just be added internally without being persisted
+	 *                       (Note: you can still call persistData later to persist all the profiles)
+	 */
 	public void addProfile(Profile profile, boolean persist){
 
 		if(profile.mId == -1){
-			profile.mId = ++holder.mIncrementValue;
+			profile.mId = ++mIncrementValue;
 		}
 
-		holder.mProfiles.put(profile.mId, profile);
+		mProfiles.put(profile.mId, profile);
 
 		if(persist){
 			persistData();
@@ -200,10 +322,15 @@ public class ProfileManager {
 		}
 	}
 
+	/**
+	 * Deletes a given profile. These changes will be persisted immediatly.
+	 *
+	 * @param profile the profile to delete
+	 */
 	public void deleteProfile(Profile profile){
-		if(this.holder.mProfiles.containsKey(profile.mId)){
+		if(this.mProfiles.containsKey(profile.mId)){
 			Profile p = getProfile(profile.mId);
-			this.holder.mProfiles.remove(profile.mId);
+			this.mProfiles.remove(profile.mId);
 
 			if(p.mActivated || this.mCurrentActivatedProfile.mId == p.mId){
 				mCurrentActivatedProfile = mRandomProfile;
@@ -220,11 +347,19 @@ public class ProfileManager {
 		}
 	}
 
+	/**
+	 * Removes all profiles.
+	 */
 	public void clearProfiles(){
-		holder.mProfiles.clear();
+		mProfiles.clear();
 		persistData();
 	}
 
+	/**
+	 * Makes a given profile active.
+	 *
+	 * @param profile the profile to activate
+	 */
 	public void activateProfile(Profile profile){
 		if(profile.equals(this.mCurrentActivatedProfile)) return;
 
@@ -235,35 +370,68 @@ public class ProfileManager {
 
 		profile.mActivated = true;
 		this.mCurrentActivatedProfile = profile;
-		this.holder.mProfiles.put(profile.mId, profile);
+		this.mProfiles.put(profile.mId, profile);
 		persistData();
 	}
 
+	/**
+	 * Checks if the "random" profile is currently active
+	 *
+	 * @return true,  if active
+	 *         false, otherwise
+	 */
 	public boolean isRandomActive(){
 		return this.mCurrentActivatedProfile.equals(this.mRandomProfile);
 	}
 
+	/**
+	 * Retrieves the "random" profile
+	 *
+	 * @return the "random" profile
+	 */
 	public Profile getRandomProfile(){
 		return this.mRandomProfile;
 	}
 
+	/**
+	 * Retrieves the currently active profile
+	 *
+	 * @return the active profile
+	 */
 	public Profile getCurrentActivatedProfile(){
 		return mCurrentActivatedProfile;
 	}
 
+	/**
+	 * Sets the list adapter that should also be managed by the profile manager
+	 *
+	 * @param profileListAdapter the list adapter to manage
+	 */
 	public void setProfileListAdapter(ProfileManagerListAdapter profileListAdapter){
 		this.mProfileListAdapter = profileListAdapter;
 	}
 
 
+	/**
+	 * Retrieves the list adapter, that is being managed by the profile manager
+	 * @return the list adapter
+	 */
 	public ProfileManagerListAdapter getProfileListAdapter(){
 		return this.mProfileListAdapter;
 	}
 
+	/**
+	 * Retrieves the number of profiles
+	 *
+	 * @return the number of profiles
+	 */
 	public int getNumberOfProfiles(){
-		return holder.mProfiles.size();
+		return mProfiles.size();
 	}
 
+	/**
+	 * Fills the profiles manager with default profiles
+	 */
 	public void fillWithDefaultData(){
 		Profile windowsVista = new Profile(
 				0,
@@ -385,7 +553,7 @@ public class ProfileManager {
 		paranoidProfile.mActivated = true;
 		this.addProfile(paranoidProfile, false);
 
-		holder.mIncrementValue = 8;
+		mIncrementValue = 8;
 		this.mCurrentActivatedProfile = paranoidProfile;
 
 		persistData();

+ 9 - 3
src/de/tudarmstadt/informatik/hostage/ui2/activity/MainActivity.java

@@ -400,6 +400,7 @@ public class MainActivity extends Activity {
 		}
 
 		if (fragment != null) {
+			getFragmentManager().popBackStackImmediate(HomeFragment.class.getName(), 0);
 			// update selected item and title, then close the drawer if needed
 			injectFragment(fragment);// , false, menuItemPosition);
 
@@ -533,9 +534,14 @@ public class MainActivity extends Activity {
 	}
 
 	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), APPLICATION_INFO(7,
-				AboutFragment.class);
+		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),
+		APPLICATION_INFO(7, AboutFragment.class);
 
 		private int value;
 		private Class<?> klass;

+ 118 - 114
src/de/tudarmstadt/informatik/hostage/ui2/adapter/ProfileManagerListAdapter.java

@@ -19,7 +19,7 @@ import java.util.LinkedList;
 import java.util.List;
 
 import de.tudarmstadt.informatik.hostage.R;
-import de.tudarmstadt.informatik.hostage.dao.ProfileManager;
+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;
@@ -64,123 +64,127 @@ public class ProfileManagerListAdapter extends ArrayAdapter<Profile> {
 
 	    final Profile item = values.get(position);
 
-	    if(rowView == null){
-		    rowView = inflater.inflate(R.layout.profile_manager_list_item, parent, false);
-
-		    holder = new ViewHolder();
-		    holder.labelView = (TextView) rowView.findViewById(R.id.profile_manager_item_label);
-		    holder.textView = (TextView) rowView.findViewById(R.id.profile_manager_item_text);
-		    holder.imageSelected = (ImageView) rowView.findViewById(R.id.profile_manager_item_activated);
-		    holder.itemIcon = (ImageView) rowView.findViewById(R.id.profile_manager_item_image);
-		    holder.buttonEdit = (ImageButton) rowView.findViewById(R.id.profile_manager_item_button_edit);
-		    holder.buttonDelete = (ImageButton) rowView.findViewById(R.id.profile_manager_item_button_delete);
-			holder.seperator = rowView.findViewById(R.id.profile_manager_item_seperator);
-			holder.badgesContainer = (FlowLayout) rowView.findViewById(R.id.badges_container);
-
-		    rowView.setTag(holder);
+	    if(item.mShowTooltip){
+		    rowView = inflater.inflate(R.layout.profile_manager_list_item_help, parent, false);
 	    } else {
-		    holder = (ViewHolder) rowView.getTag();
-	    }
-
-	    ((SwipeListView)parent).recycle(rowView, position);
-
-	    holder.textView.setText(item.mText);
-	    holder.labelView.setText(item.mLabel);
-
-	    if(item.getIconBitmap() != null){
-	        //Bitmap bitmap = Bitmap.createScaledBitmap(item.getIconBitmap(), 32, 32, true);
-	        holder.itemIcon.setImageBitmap(item.getIconBitmap());
-	    } else {
-		    holder.itemIcon.setImageBitmap(BitmapFactory.decodeResource(MainActivity.context.getResources(), R.drawable.ic_launcher));
-	    }
-
-		holder.buttonEdit.setOnClickListener(new View.OnClickListener() {
-			@Override
-			public void onClick(View v) {
-				Intent intent = new Intent(context, ProfileEditActivity.class);
-				intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-				intent.putExtra("profile_id", item.mId);
-				//intent.putExtra("profile", item);
-				context.startActivity(intent);
-			}
-		});
-
-		holder.buttonDelete.setOnClickListener(new View.OnClickListener() {
-			@Override
-			public void onClick(View v) {
-				new AlertDialog.Builder(context)
-						.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();
-								list.closeOpenedItems();
-							}
-						})
-						.setIcon(android.R.drawable.ic_dialog_alert)
-						.show();
-			}
-		});
-
-	    holder.badgesContainer.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(context, R.style.ProfileManagerListBadge));
-		    textView.setText(protocol);
-		    holder.badgesContainer.addView(textView);
-	    }
+		    if (rowView == null || rowView.getTag() == null) {
+			    rowView = inflater.inflate(R.layout.profile_manager_list_item, parent, false);
+
+			    holder = new ViewHolder();
+			    holder.labelView = (TextView) rowView.findViewById(R.id.profile_manager_item_label);
+			    holder.textView = (TextView) rowView.findViewById(R.id.profile_manager_item_text);
+			    holder.imageSelected = (ImageView) rowView.findViewById(R.id.profile_manager_item_activated);
+			    holder.itemIcon = (ImageView) rowView.findViewById(R.id.profile_manager_item_image);
+			    holder.buttonEdit = (ImageButton) rowView.findViewById(R.id.profile_manager_item_button_edit);
+			    holder.buttonDelete = (ImageButton) rowView.findViewById(R.id.profile_manager_item_button_delete);
+			    holder.seperator = rowView.findViewById(R.id.profile_manager_item_seperator);
+			    holder.badgesContainer = (FlowLayout) rowView.findViewById(R.id.badges_container);
+
+			    rowView.setTag(holder);
+		    } else {
+			    holder = (ViewHolder) rowView.getTag();
+		    }
+
+		    ((SwipeListView) parent).recycle(rowView, position);
+
+		    holder.textView.setText(item.mText);
+		    holder.labelView.setText(item.mLabel);
+
+		    if (item.getIconBitmap() != null) {
+			    //Bitmap bitmap = Bitmap.createScaledBitmap(item.getIconBitmap(), 32, 32, true);
+			    holder.itemIcon.setImageBitmap(item.getIconBitmap());
+		    } else {
+			    holder.itemIcon.setImageBitmap(BitmapFactory.decodeResource(MainActivity.context.getResources(), R.drawable.ic_launcher));
+		    }
+
+		    holder.buttonEdit.setOnClickListener(new View.OnClickListener() {
+			    @Override
+			    public void onClick(View v) {
+				    Intent intent = new Intent(context, ProfileEditActivity.class);
+				    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+				    intent.putExtra("profile_id", item.mId);
+				    //intent.putExtra("profile", item);
+				    context.startActivity(intent);
+			    }
+		    });
+
+		    holder.buttonDelete.setOnClickListener(new View.OnClickListener() {
+			    @Override
+			    public void onClick(View v) {
+				    new AlertDialog.Builder(context)
+						    .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();
+								    list.closeOpenedItems();
+							    }
+						    })
+						    .setIcon(android.R.drawable.ic_dialog_alert)
+						    .show();
+			    }
+		    });
+
+		    holder.badgesContainer.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(context, R.style.ProfileManagerListBadge));
+			    textView.setText(protocol);
+			    holder.badgesContainer.addView(textView);
+		    }
+
+		    if (!hasProtocols) {
+			    holder.badgesContainer.setVisibility(View.INVISIBLE);
+		    } else {
+			    holder.badgesContainer.setVisibility(View.VISIBLE);
+		    }
+
+		    RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) holder.textView.getLayoutParams();
+
+		    if (!item.mActivated) {
+			    lp.setMargins(0, 0, 0, 0);
+
+			    holder.textView.setLayoutParams(lp);
+
+			    holder.imageSelected.setVisibility(View.GONE);
+		    } else {
+				/*float d = context.getResources().getDisplayMetrics().density;
+				int dm = (int)(20 * d);
+
+				lp.setMargins(0,0,dm,0);
+
+				holder.textView.setLayoutParams(lp);*/
+
+			    holder.imageSelected.setVisibility(View.VISIBLE);
+		    }
+
+		    if (!item.isEditable()) {
+			    holder.buttonDelete.setVisibility(View.GONE);
+			    holder.seperator.setVisibility(View.GONE);
+		    } else {
+			    holder.buttonDelete.setVisibility(View.VISIBLE);
+			    holder.seperator.setVisibility(View.VISIBLE);
+		    }
 
-	    if(!hasProtocols){
-		    holder.badgesContainer.setVisibility(View.INVISIBLE);
-	    } else {
-		    holder.badgesContainer.setVisibility(View.VISIBLE);
 	    }
 
-		RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) holder.textView.getLayoutParams();
-
-        if(!item.mActivated){
-            lp.setMargins(0, 0, 0, 0);
-
-	        holder.textView.setLayoutParams(lp);
-
-	        holder.imageSelected.setVisibility(View.GONE);
-        } else {
-			/*float d = context.getResources().getDisplayMetrics().density;
-			int dm = (int)(20 * d);
-
-			lp.setMargins(0,0,dm,0);
-
-			holder.textView.setLayoutParams(lp);*/
-
-			holder.imageSelected.setVisibility(View.VISIBLE);
-		}
-
-
-		if(!item.isEditable()){
-			holder.buttonDelete.setVisibility(View.GONE);
-			holder.seperator.setVisibility(View.GONE);
-		} else {
-			holder.buttonDelete.setVisibility(View.VISIBLE);
-			holder.seperator.setVisibility(View.VISIBLE);
-		}
-
         return rowView;
     }
 

+ 1 - 1
src/de/tudarmstadt/informatik/hostage/ui2/adapter/ServicesListAdapter.java

@@ -131,7 +131,7 @@ public class ServicesListAdapter extends ArrayAdapter<ServicesListItem> {
 	private void updateStatus(ServicesListItem item, ViewHolder holder) {
 		if (MainActivity.getInstance().getHostageService().isRunning(item.protocol)) {
 			holder.activated.setChecked(true);
-			if (!(MainActivity.getInstance().getHostageService().getNumberOfActiveConnections(item.protocol) > 0)) {
+			if (!(MainActivity.getInstance().getHostageService().hasProtocolActiveAttacks(item.protocol))) {
 				if (item.attacks > 0) {
 					setBackground(holder, R.drawable.services_circle_yellow);
 				} else {

+ 1 - 1
src/de/tudarmstadt/informatik/hostage/ui2/fragment/HomeFragment.java

@@ -24,7 +24,7 @@ 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.dao.ProfileManager;
+import de.tudarmstadt.informatik.hostage.persistence.ProfileManager;
 import de.tudarmstadt.informatik.hostage.deprecated.UglyDbHelper;
 import de.tudarmstadt.informatik.hostage.model.Profile;
 import de.tudarmstadt.informatik.hostage.ui.LogFilter;

+ 1 - 3
src/de/tudarmstadt/informatik/hostage/ui2/fragment/ProfileEditFragment.java

@@ -13,12 +13,10 @@ import android.net.Uri;
 import android.os.Bundle;
 import android.preference.CheckBoxPreference;
 import android.preference.EditTextPreference;
-import android.preference.MultiSelectListPreference;
 import android.preference.Preference;
 import android.preference.PreferenceCategory;
 import android.preference.PreferenceFragment;
 import android.preference.PreferenceManager;
-import android.preference.PreferenceScreen;
 import android.provider.MediaStore;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -27,7 +25,7 @@ import android.widget.LinearLayout;
 import java.util.HashMap;
 
 import de.tudarmstadt.informatik.hostage.R;
-import de.tudarmstadt.informatik.hostage.dao.ProfileManager;
+import de.tudarmstadt.informatik.hostage.persistence.ProfileManager;
 import de.tudarmstadt.informatik.hostage.model.Profile;
 
 /**

+ 17 - 1
src/de/tudarmstadt/informatik/hostage/ui2/fragment/ProfileManagerFragment.java

@@ -15,7 +15,7 @@ import com.fortysevendeg.android.swipelistview.BaseSwipeListViewListener;
 import java.util.List;
 
 import de.tudarmstadt.informatik.hostage.R;
-import de.tudarmstadt.informatik.hostage.dao.ProfileManager;
+import de.tudarmstadt.informatik.hostage.persistence.ProfileManager;
 import de.tudarmstadt.informatik.hostage.model.Profile;
 import de.tudarmstadt.informatik.hostage.ui2.activity.ProfileEditActivity;
 import de.tudarmstadt.informatik.hostage.ui2.adapter.ProfileManagerListAdapter;
@@ -47,12 +47,28 @@ public class ProfileManagerFragment extends Fragment {
 
         List<Profile> strList = pmanager.getProfilesList();
 
+	    if(strList.size() > 0){
+		    Profile tProfile = new Profile();
+		    tProfile.mShowTooltip = true;
+
+			strList.add(1, tProfile);
+	    }
+
 		mAdapter = new ProfileManagerListAdapter(getActivity(), strList, list);
 		pmanager.setProfileListAdapter(mAdapter);
 
         list.setAdapter(mAdapter);
 
 		list.setSwipeListViewListener(new BaseSwipeListViewListener() {
+			@Override
+			public void onOpened(int position, boolean toRight){
+				Profile profile = mAdapter.getItem(position);
+				if(profile.mShowTooltip){
+					mAdapter.remove(profile);
+					list.dismiss(position);
+				}
+			}
+
 			@Override
 			public void onClickFrontView(int position) {
 				Profile profile = mAdapter.getItem(position);