Browse Source

fixed merge conflict

Alexander Brakowski 9 years ago
parent
commit
4024ac8b1b
28 changed files with 2345 additions and 116 deletions
  1. 35 1
      AndroidManifest.xml
  2. 28 18
      res/layout/activity_p2_psync.xml
  3. 37 0
      res/values-de/strings.xml
  4. 2 0
      res/values/arrays.xml
  5. 1 1
      res/values/protocols.xml
  6. 37 0
      res/values/strings.xml
  7. 23 0
      res/xml/authenticator.xml
  8. 16 2
      res/xml/settings_preferences.xml
  9. 25 0
      res/xml/syncadapter.xml
  10. 1 1
      src/de/tudarmstadt/informatik/hostage/persistence/HostageDBOpenHelper.java
  11. 97 0
      src/de/tudarmstadt/informatik/hostage/sync/android/HostageAccountService.java
  12. 104 0
      src/de/tudarmstadt/informatik/hostage/sync/android/SyncAdapter.java
  13. 52 0
      src/de/tudarmstadt/informatik/hostage/sync/android/SyncService.java
  14. 227 0
      src/de/tudarmstadt/informatik/hostage/sync/android/SyncUtils.java
  15. 2 2
      src/de/tudarmstadt/informatik/hostage/sync/p2p/P2PSyncActivity.java
  16. 52 85
      src/de/tudarmstadt/informatik/hostage/sync/tracing/TracingSyncService.java
  17. 86 0
      src/de/tudarmstadt/informatik/hostage/sync/wifi_direct/BackgroundTask.java
  18. 293 0
      src/de/tudarmstadt/informatik/hostage/sync/wifi_direct/WiFiP2pBroadcastReceiver.java
  19. 167 0
      src/de/tudarmstadt/informatik/hostage/sync/wifi_direct/WiFiP2pClientTask.java
  20. 111 0
      src/de/tudarmstadt/informatik/hostage/sync/wifi_direct/WiFiP2pEventHandler.java
  21. 42 0
      src/de/tudarmstadt/informatik/hostage/sync/wifi_direct/WiFiP2pSerializableObject.java
  22. 131 0
      src/de/tudarmstadt/informatik/hostage/sync/wifi_direct/WiFiP2pServerTask.java
  23. 75 0
      src/de/tudarmstadt/informatik/hostage/sync/wifi_direct/sync_tasks/SyncClientTask.java
  24. 92 0
      src/de/tudarmstadt/informatik/hostage/sync/wifi_direct/sync_tasks/SyncHostTask.java
  25. 554 0
      src/de/tudarmstadt/informatik/hostage/sync/wifi_direct/ui/WiFiP2pSyncActivity.java
  26. 4 0
      src/de/tudarmstadt/informatik/hostage/ui/activity/MainActivity.java
  27. 48 1
      src/de/tudarmstadt/informatik/hostage/ui/fragment/PreferenceHostageFragment.java
  28. 3 5
      src/de/tudarmstadt/informatik/hostage/ui/fragment/RecordOverviewFragment.java

+ 35 - 1
AndroidManifest.xml

@@ -21,6 +21,12 @@
     <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
     <uses-permission android:name="android.permission.NFC" />
     <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
+    <!-- Required to register a SyncStatusObserver to display a "syncing..." progress indicator. -->
+    <uses-permission android:name="android.permission.READ_SYNC_STATS"/>
+    <!-- Required to enable our SyncAdapter after it's created. -->
+    <uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS"/>
+    <!-- Required because we're manually creating a new account. -->
+    <uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS"/>
     <!--
     	<uses-permission android:name="android.permission.BLUETOOTH" />
     <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
@@ -109,14 +115,42 @@
             android:exported="false" >
         </provider>
 
-        <activity
+        <!--<activity
             android:name=".sync.p2p.P2PSyncActivity"
             android:label="@string/title_activity_p2_psync"
             android:parentActivityName=".ui.activity.MainActivity" >
             <meta-data
                 android:name="android.support.PARENT_ACTIVITY"
                 android:value="de.tudarmstadt.informatik.hostage.ui.activity.MainActivity" />
+        </activity>-->
+
+        <activity
+            android:name=".sync.wifi_direct.ui.WiFiP2pSyncActivity"
+            android:label="@string/title_activity_p2_psync"
+            android:parentActivityName=".ui.activity.MainActivity" >
+            <meta-data
+                android:name="android.support.PARENT_ACTIVITY"
+                android:value="de.tudarmstadt.informatik.hostage.ui.activity.MainActivity" />
         </activity>
+
+        <service android:name=".sync.android.SyncService"
+                 android:exported="true">
+            <intent-filter>
+                <action android:name="android.content.SyncAdapter" />
+            </intent-filter>
+
+            <meta-data android:name="android.content.SyncAdapter"
+                       android:resource="@xml/syncadapter" />
+        </service>
+
+        <service android:name=".sync.android.HostageAccountService">
+            <intent-filter>
+                <action android:name="android.accounts.AccountAuthenticator" />
+            </intent-filter>
+
+            <meta-data android:name="android.accounts.AccountAuthenticator"
+                       android:resource="@xml/authenticator" />
+        </service>
     </application>
 
 </manifest>

+ 28 - 18
res/layout/activity_p2_psync.xml

@@ -8,11 +8,13 @@
     android:paddingBottom="@dimen/activity_vertical_margin"
     tools:context="de.tudarmstadt.informatik.hostage.sync.p2p.P2PSyncActivity">
 
+
+
     <TextView
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:textAppearance="?android:attr/textAppearanceMedium"
-        android:text="Your Device"
+        android:text="@string/Your_Device"
         android:id="@+id/textView4"
         android:layout_alignParentLeft="true"
         android:layout_alignParentStart="true"
@@ -24,7 +26,7 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:textAppearance="?android:attr/textAppearanceSmall"
-        android:text="Change device name"
+        android:text="@string/Change_Device_Name"
         android:id="@+id/txtP2PChangeDeviceName"
         android:layout_alignParentTop="true"
         android:layout_alignParentRight="true"
@@ -49,7 +51,7 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:textAppearance="?android:attr/textAppearanceSmall"
-            android:text="Device name"
+            android:text="@string/Device_Name"
             android:id="@+id/textView"
             android:textStyle="bold" />
 
@@ -69,7 +71,7 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:textAppearance="?android:attr/textAppearanceSmall"
-            android:text="Device status"
+            android:text="@string/Device_Status"
             android:id="@+id/textView2"
             android:layout_below="@+id/textView"
             android:layout_alignParentLeft="true"
@@ -90,16 +92,13 @@
             android:layout_marginTop="6dp" />
     </RelativeLayout>
 
-    <ViewAnimator
+
+
+    <RelativeLayout
+        android:id="@+id/list_container"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:id="@+id/viewAnimator"
-        android:layout_below="@+id/device_info_panel"
-        android:layout_alignParentBottom="true"
-        android:layout_alignParentRight="true"
-        android:layout_alignParentEnd="true"
-        android:layout_alignParentLeft="true"
-        android:layout_alignParentStart="true">
+        android:layout_below="@+id/device_info_panel">
 
         <RelativeLayout
             android:layout_width="fill_parent"
@@ -107,10 +106,11 @@
             android:visibility="gone"
             android:id="@+id/welcomeContainer">
 
+            <!-- We are sorry, but WiFi Direct does not seem to be supported by this device. -->
             <TextView
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:text="We are sorry, but WiFi Direct does not seem to be supported by this device."
+                android:text="@string/Wifi_Direct_Not_suppported"
                 android:id="@+id/txtP2PNotAvailable"
                 android:textAlignment="center"
                 android:gravity="center_horizontal"
@@ -124,16 +124,14 @@
         <RelativeLayout
             android:layout_width="fill_parent"
             android:layout_height="fill_parent"
-            android:layout_alignParentBottom="true"
-            android:layout_alignParentRight="true"
-            android:layout_alignParentEnd="true"
+
             android:id="@+id/devicesContainer">
 
             <TextView
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:textAppearance="?android:attr/textAppearanceMedium"
-                android:text="Available Devices"
+                android:text="@string/Available_Devices"
                 android:id="@+id/textView5"
                 android:layout_alignParentTop="true"
                 android:layout_alignParentLeft="true"
@@ -152,13 +150,25 @@
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:textAppearance="?android:attr/textAppearanceSmall"
-                android:text="Looking for devices..."
+                android:text="@string/Looking_For_Devices_Progress_Title"
                 android:id="@+id/txtP2PSearchProgress"
                 android:layout_centerVertical="true"
                 android:layout_centerHorizontal="true" />
 
         </RelativeLayout>
 
+    </RelativeLayout>
+
+    <ViewAnimator
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:id="@+id/viewAnimator"
+        android:layout_below="@+id/device_info_panel"
+        android:layout_alignParentBottom="true"
+        android:layout_alignParentRight="true"
+        android:layout_alignParentEnd="true"
+        android:layout_alignParentLeft="true"
+        android:layout_alignParentStart="true">
     </ViewAnimator>
 
 </RelativeLayout>

+ 37 - 0
res/values-de/strings.xml

@@ -152,6 +152,39 @@
     <string name="stats_per_cent_all">% von allen</string>
     <string name="pie_all">Alle</string>
 
+
+    <string name="CONNECTION_LOST_MESSAGE">Verbindung verloren, Wifi Direct muss erneut aktiviert werden.</string>
+    <string name="COULD_NOT_CONNECT_MESSAGE">Could not connect to device. Retry.</string>
+
+    <string name="SYNCHRONIZATION_COMPLETE_MESSAGE">Synchronisierung abgeschlossen.</string>
+    <string name="SYNCHRONIZATION_FAILED_MESSAGE">Synchronisierung konnte nicht abgeschlossen werden. Versuche es erneut.</string>
+
+    <string name="PERFORMING_TASK_AS_HOST">Verbunden als Host.</string>
+    <string name="PERFORMING_TASK_AS_CLIENT">Verbunden als Client.</string>
+
+    <string name="ACTIONBAR_TITLE">P2P Synchronisierung</string>
+    <string name="PROGRESS_TITLE_LOADING">Empfangen...</string>
+    <string name="PROGRESS_TITLE_CONNECTING">Verbinden...</string>
+
+    <string name="DEVICE_STATUS_AVAILABLE">Bereit</string>
+    <string name="DEVICE_STATUS_INVITED">Eingeladen</string>
+    <string name="DEVICE_STATUS_CONNECTED">Verbunden</string>
+    <string name="DEVICE_STATUS_FAILED">Fehlgeschlagen</string>
+    <string name="DEVICE_STATUS_UNAVAILABLE">Unerreichbar</string>
+    <string name="DEVICE_STATUS_UNKNOWN">Status ist unbekannt</string>
+
+    <string name="WIFI_STATUS_DISABLED_MESSAGE">WiFi Direct ist nicht vorhanden, bitte aktiviere WiFi Direct.</string>
+    <string name="WIFI_STATUS_ENABLE_BUTTON">Aktivieren</string>
+    <string name="CANCEL_BUTTON_TITLE">Abbrechen</string>
+
+    <string name="Your_Device">Eigene Ger&#228;te Informationen</string>
+    <string name="Change_Device_Name">Ger&#228;tename &#228;ndern</string>
+    <string name="Device_Name">Ger&#228;tename</string>
+    <string name="Device_Status">Ger&#228;testatus</string>
+    <string name="Wifi_Direct_Not_suppported">Das Ger&#228;t unterst&#252;tzt kein Wifi Direct.</string>
+    <string name="Available_Devices">Vorhandene Ger&#228;te</string>
+    <string name="Looking_For_Devices_Progress_Title">Suche andere Ger&#228;te.</string>
+
 	<string name="record_details_received">EMPFANGEN</string>
 	<string name="record_details_sent">GESENDET</string>
 	<string name="record_details_info" formatted="false">von %s an %s\n%s um %s Uhr</string>
@@ -187,4 +220,8 @@
     <string name="rec_via_nfc">&#220;ber NFC</string>
     <string name="rec_via_online">&#220;ber Online Datenbank</string>
     <string name="title_activity_p2_psync">WifiDirect Synchronization</string>
+    <string name="pref_sync_countries_dialog">Länderauswahl</string>
+    <string name="pref_sync_countries_desc">Nur Angriffdaten von diesen Ländern herunterladen</string>
+    <string name="pref_sync_countries">Länder</string>
+    <string name="pref_download_server">Download server</string>
 </resources>

+ 2 - 0
res/values/arrays.xml

@@ -12,4 +12,6 @@
         <item>All</item>
     </string-array>
 
+    <string-array name="pref_sync_countries_default">
+    </string-array>
 </resources>

+ 1 - 1
res/values/protocols.xml

@@ -14,7 +14,7 @@
         <item>TELNET</item>
     </string-array>
 
-	<string-array name="protocols_description">
+    <string-array name="protocols_description">
 		<item>A service for testing and measurement of round-trip times in IP networks</item>
 		<item>A protocol used to transfer files from one host to another host</item>
 		<item>A protocol mirrors an incoming connection back to the attacker on the same port, that it is running on</item>

+ 37 - 0
res/values/strings.xml

@@ -174,6 +174,39 @@
     <string name="stats_per_cent_all">% of all</string>
     <string name="pie_all">All</string>
 
+
+    <string name="CONNECTION_LOST_MESSAGE">Connection lost permanently, please enable wifi direct.</string>
+    <string name="COULD_NOT_CONNECT_MESSAGE">Could not connect to device. Retry.</string>
+
+    <string name="SYNCHRONIZATION_COMPLETE_MESSAGE">Synchronization complete.</string>
+    <string name="SYNCHRONIZATION_FAILED_MESSAGE">Could not synchronize devices. Retry</string>
+
+    <string name="PERFORMING_TASK_AS_HOST">Acting as Host.</string>
+    <string name="PERFORMING_TASK_AS_CLIENT">Acting as Client.</string>
+
+    <string name="ACTIONBAR_TITLE">WifiDirect Synchronization</string>
+    <string name="PROGRESS_TITLE_LOADING">Loading...</string>
+    <string name="PROGRESS_TITLE_CONNECTING">Connecting...</string>
+
+    <string name="DEVICE_STATUS_AVAILABLE">Available</string>
+    <string name="DEVICE_STATUS_INVITED">Invited</string>
+    <string name="DEVICE_STATUS_CONNECTED">Connected</string>
+    <string name="DEVICE_STATUS_FAILED">Failed</string>
+    <string name="DEVICE_STATUS_UNAVAILABLE">Unavailable</string>
+    <string name="DEVICE_STATUS_UNKNOWN">Unknown</string>
+
+    <string name="WIFI_STATUS_DISABLED_MESSAGE">WiFi Direct down, please enable WiFi Direct</string>
+    <string name="WIFI_STATUS_ENABLE_BUTTON">Enable WiFi Direct</string>
+    <string name="CANCEL_BUTTON_TITLE">Cancel</string>
+
+    <string name="Your_Device">Own Device Information</string>
+    <string name="Change_Device_Name">Change your device name</string>
+    <string name="Device_Name">Device Name</string>
+    <string name="Device_Status">Device Status</string>
+    <string name="Wifi_Direct_Not_suppported">Your device does not support Wifi Direct.</string>
+    <string name="Available_Devices">Available Devices</string>
+    <string name="Looking_For_Devices_Progress_Title">Scanning for other devices.</string>
+
 	<string name="record_details_received">RECEIVED</string>
 	<string name="record_details_sent">SENT</string>
 	<string name="record_details_info" formatted="false">from %s to %s\n%s at %s</string>
@@ -210,4 +243,8 @@
     <string name="rec_via_nfc">Via NFC</string>
     <string name="rec_via_online">Via Online Database</string>
     <string name="title_activity_p2_psync">WifiDirect Synchronization</string>
+    <string name="pref_sync_countries_dialog">Country selection</string>
+    <string name="pref_sync_countries_desc">Only download attack data of these countries</string>
+    <string name="pref_sync_countries">Countries</string>
+    <string name="pref_download_server">Download server</string>
 </resources>

+ 23 - 0
res/xml/authenticator.xml

@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2013 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
+                       android:accountType="de.tudarmstadt.informatik.hostage"
+                       android:icon="@drawable/ic_launcher"
+                       android:smallIcon="@drawable/ic_launcher"
+                       android:label="@string/app_name"
+        />

+ 16 - 2
res/xml/settings_preferences.xml

@@ -26,16 +26,30 @@
 	</PreferenceCategory>
 
 	<PreferenceCategory android:title="@string/pref_upload" >
-		<CheckBoxPreference
+		<!--<CheckBoxPreference
 			android:defaultValue="false"
 			android:key="pref_auto_synchronize"
 			android:summary="@string/pref_auto_synchronize_summ"
-			android:title="@string/pref_auto_synchronize_title" />
+			android:title="@string/pref_auto_synchronize_title" />-->
 
 		<EditTextPreference
 				android:key="pref_upload_server"
 				android:defaultValue="https://ssi.cased.de"
 				android:title="@string/pref_upload_server" />
+
+        <EditTextPreference
+            android:key="pref_download_server"
+            android:defaultValue="http://ssi.cased.de/api"
+            android:title="@string/pref_download_server" />
+
+        <MultiSelectListPreference
+            android:dialogTitle="@string/pref_sync_countries_dialog"
+            android:key="pref_sync_countries"
+            android:summary="@string/pref_sync_countries_desc"
+            android:title="@string/pref_sync_countries"
+            android:entries="@array/pref_sync_countries_default"
+            android:entryValues="@array/pref_sync_countries_default"
+            />
 	</PreferenceCategory>
 
 	<PreferenceCategory android:title="@string/advanced_settings">

+ 25 - 0
res/xml/syncadapter.xml

@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2013 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
+              android:contentAuthority="de.tudarmstadt.informatik.hostage.androidsync"
+              android:accountType="de.tudarmstadt.informatik.hostage"
+              android:userVisible="true"
+              android:supportsUploading="true"
+              android:allowParallelSyncs="false"
+              android:isAlwaysSyncable="true"
+        />

+ 1 - 1
src/de/tudarmstadt/informatik/hostage/persistence/HostageDBOpenHelper.java

@@ -2045,7 +2045,7 @@ public class HostageDBOpenHelper extends SQLiteOpenHelper {
 
         String filterQuery = this.selectionQueryFromFilter(filter, AttackEntry.COLUMN_NAME_ATTACK_ID);
 
-        String attackPerBSSID_Query = "SELECT " + NetworkEntry.COLUMN_NAME_BSSID + " , " + "COUNT( " + AttackEntry.COLUMN_NAME_ATTACK_ID + "  ) " + " "
+        String attackPerBSSID_Query = "SELECT " + NetworkEntry.TABLE_NAME + "." + NetworkEntry.COLUMN_NAME_BSSID + " , " + "COUNT( " + AttackEntry.COLUMN_NAME_ATTACK_ID + "  ) " + " "
                 + " FROM " + AttackEntry.TABLE_NAME + " a " + " , " + NetworkEntry.TABLE_NAME
                 + " WHERE " + " a." + AttackEntry.COLUMN_NAME_ATTACK_ID + " IN " + " ( " + filterQuery + " ) "
                 + " GROUP BY " + NetworkEntry.TABLE_NAME + "." + NetworkEntry.COLUMN_NAME_BSSID;

+ 97 - 0
src/de/tudarmstadt/informatik/hostage/sync/android/HostageAccountService.java

@@ -0,0 +1,97 @@
+package de.tudarmstadt.informatik.hostage.sync.android;
+
+import android.accounts.AbstractAccountAuthenticator;
+import android.accounts.Account;
+import android.accounts.AccountAuthenticatorResponse;
+import android.accounts.NetworkErrorException;
+import android.app.Service;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.util.Log;
+
+/**
+ * Created by abrakowski
+ */
+public class HostageAccountService extends Service {
+    private static final String TAG = "HostageAccountService";
+    private static final String ACCOUNT_TYPE = "de.tudarmstadt.informatik.hostage";
+    public static final String ACCOUNT_NAME = "TraCINg";
+    private Authenticator mAuthenticator;
+
+
+    public static Account GetAccount() {
+        final String accountName = ACCOUNT_NAME;
+        return new Account(accountName, ACCOUNT_TYPE);
+    }
+
+    @Override
+    public void onCreate() {
+        Log.i(TAG, "Service created");
+        mAuthenticator = new Authenticator(this);
+    }
+
+    @Override
+    public void onDestroy() {
+        Log.i(TAG, "Service destroyed");
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return mAuthenticator.getIBinder();
+    }
+
+    public class Authenticator extends AbstractAccountAuthenticator {
+        public Authenticator(Context context) {
+            super(context);
+        }
+
+        @Override
+        public Bundle editProperties(AccountAuthenticatorResponse accountAuthenticatorResponse,
+                                     String s) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public Bundle addAccount(AccountAuthenticatorResponse accountAuthenticatorResponse,
+                                 String s, String s2, String[] strings, Bundle bundle)
+                throws NetworkErrorException {
+            return null;
+        }
+
+        @Override
+        public Bundle confirmCredentials(AccountAuthenticatorResponse accountAuthenticatorResponse,
+                                         Account account, Bundle bundle)
+                throws NetworkErrorException {
+            return null;
+        }
+
+        @Override
+        public Bundle getAuthToken(AccountAuthenticatorResponse accountAuthenticatorResponse,
+                                   Account account, String s, Bundle bundle)
+                throws NetworkErrorException {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public String getAuthTokenLabel(String s) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public Bundle updateCredentials(AccountAuthenticatorResponse accountAuthenticatorResponse,
+                                        Account account, String s, Bundle bundle)
+                throws NetworkErrorException {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public Bundle hasFeatures(AccountAuthenticatorResponse accountAuthenticatorResponse,
+                                  Account account, String[] strings)
+                throws NetworkErrorException {
+            throw new UnsupportedOperationException();
+        }
+    }
+}

+ 104 - 0
src/de/tudarmstadt/informatik/hostage/sync/android/SyncAdapter.java

@@ -0,0 +1,104 @@
+package de.tudarmstadt.informatik.hostage.sync.android;
+
+import android.accounts.Account;
+import android.content.AbstractThreadedSyncAdapter;
+import android.content.ContentProviderClient;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.SyncResult;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.util.Log;
+
+import java.io.StringWriter;
+import java.util.ArrayList;
+
+import de.tudarmstadt.informatik.hostage.logging.Record;
+import de.tudarmstadt.informatik.hostage.persistence.HostageDBOpenHelper;
+import de.tudarmstadt.informatik.hostage.ui.model.LogFilter;
+
+/**
+ * Created by abrakowski
+ */
+public class SyncAdapter extends AbstractThreadedSyncAdapter {
+    public static final String TAG = "SyncAdapter";
+    private final SharedPreferences pref;
+    private final SharedPreferences.Editor editor;
+    private final HostageDBOpenHelper dbh;
+
+    private Context context;
+
+    public SyncAdapter(Context context, boolean autoInitialize) {
+        this(context, autoInitialize, false);
+    }
+
+    public SyncAdapter(Context context, boolean autoInitialize, boolean allowParallelSyncs) {
+        super(context, autoInitialize, allowParallelSyncs);
+        this.context = context;
+
+        pref = PreferenceManager.getDefaultSharedPreferences(context);
+        editor = pref.edit();
+        dbh = new HostageDBOpenHelper(context);
+    }
+
+    /**
+     * Called by the Android system in response to a request to run the sync adapter. The work
+     * required to read data from the network, parse it, and store it in the content provider is
+     * done here. Extending AbstractThreadedSyncAdapter ensures that all methods within SyncAdapter
+     * run on a background thread. For this reason, blocking I/O and other long-running tasks can be
+     * run <em>in situ</em>, and you don't have to set up a separate thread for them.
+     .
+     *
+     * <p>This is where we actually perform any work required to perform a sync.
+     * {@link AbstractThreadedSyncAdapter} guarantees that this will be called on a non-UI thread,
+     * so it is safe to peform blocking I/O here.
+     *
+     * <p>The syncResult argument allows you to pass information back to the method that triggered
+     * the sync.
+     */
+    @Override
+    public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
+        // We will only do a one-direction sync. That is, only sending data to the tracing server.
+        // For bidirectional syncing, we will still have to decide how much data should be requested from the server,
+        // because the server has relatively to a mobile device almost unlimited space.
+
+        Log.i(TAG, "Beginning network synchronization");
+
+        long lastSyncTime = pref.getLong("LAST_SYNC_TIME", 0);
+
+        String serverAddress = pref.getString("pref_upload_server", "https://ssi.cased.de"); //"https://192.168.1.118:9999"
+
+        Log.i(TAG, "Connecting to " + serverAddress);
+        LogFilter filter = new LogFilter();
+        filter.setAboveTimestamp(lastSyncTime);
+
+        ArrayList<Record> records = dbh.getRecordsForFilter(filter);
+        StringWriter writer = new StringWriter();
+
+        int size = records.size();
+        int offset = 1;
+        int currOffset = 1;
+        boolean error = false;
+        for (Record record : records) {
+            SyncUtils.appendRecordToStringWriter(record, writer);
+
+            if(currOffset == 100 || offset == size){
+                boolean success = SyncUtils.uploadRecordsToServer(writer.toString(), serverAddress);
+                if(!success){
+                    syncResult.stats.numIoExceptions++;
+                    error =  true;
+                    break;
+                }
+
+                writer.getBuffer().setLength(0);
+                currOffset = 0;
+            }
+
+            offset++;
+            currOffset++;
+        }
+
+        if(!error) pref.edit().putLong("LAST_SYNC_TIME", System.currentTimeMillis()).apply();
+        Log.i(TAG, "Network synchronization complete");
+    }
+}

+ 52 - 0
src/de/tudarmstadt/informatik/hostage/sync/android/SyncService.java

@@ -0,0 +1,52 @@
+package de.tudarmstadt.informatik.hostage.sync.android;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+import android.util.Log;
+
+/**
+ * Created by abrakowski
+ */
+public class SyncService extends Service {
+    private static final String TAG = "SyncService";
+
+    private static final Object sSyncAdapterLock = new Object();
+    private static SyncAdapter sSyncAdapter = null;
+
+    /**
+     * Thread-safe constructor, creates static {@link SyncAdapter} instance.
+     */
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        Log.i(TAG, "Service created");
+        synchronized (sSyncAdapterLock) {
+            if (sSyncAdapter == null) {
+                sSyncAdapter = new SyncAdapter(getApplicationContext(), true);
+            }
+        }
+    }
+
+    @Override
+    /**
+     * Logging-only destructor.
+     */
+    public void onDestroy() {
+        super.onDestroy();
+        Log.i(TAG, "Service destroyed");
+    }
+
+    /**
+     * Return Binder handle for IPC communication with {@link SyncAdapter}.
+     *
+     * <p>New sync requests will be sent directly to the SyncAdapter using this channel.
+     *
+     * @param intent Calling intent
+     * @return Binder handle for {@link SyncAdapter}
+     */
+    @Override
+    public IBinder onBind(Intent intent) {
+        return sSyncAdapter.getSyncAdapterBinder();
+    }
+}

+ 227 - 0
src/de/tudarmstadt/informatik/hostage/sync/android/SyncUtils.java

@@ -0,0 +1,227 @@
+package de.tudarmstadt.informatik.hostage.sync.android;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.util.Log;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpVersion;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.conn.ClientConnectionManager;
+import org.apache.http.conn.scheme.PlainSocketFactory;
+import org.apache.http.conn.scheme.Scheme;
+import org.apache.http.conn.scheme.SchemeRegistry;
+import org.apache.http.conn.ssl.SSLSocketFactory;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
+import org.apache.http.params.BasicHttpParams;
+import org.apache.http.params.HttpParams;
+import org.apache.http.params.HttpProtocolParams;
+import org.apache.http.protocol.HTTP;
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Writer;
+import java.security.KeyStore;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import de.tudarmstadt.informatik.hostage.logging.Record;
+import de.tudarmstadt.informatik.hostage.net.MySSLSocketFactory;
+
+/**
+ * Created by abrakowski
+ */
+public class SyncUtils {
+    private static final long SYNC_FREQUENCY = 60 * 60;  // 1 hour (in seconds)
+    public static final String CONTENT_AUTHORITY = "de.tudarmstadt.informatik.hostage.androidsync";
+    private static final String PREF_SETUP_COMPLETE = "sync_setup_complete";
+
+    private static final Map<String, Integer> protocolsTypeMap;
+
+    static {
+        protocolsTypeMap = new HashMap<String, Integer>();
+        protocolsTypeMap.put("ECHO", 10);
+        protocolsTypeMap.put("FTP", 0);
+        protocolsTypeMap.put("GHOST", 0);
+        protocolsTypeMap.put("HTTP", 0);
+        protocolsTypeMap.put("HTTPS", 0);
+        protocolsTypeMap.put("MySQL", 31);
+        protocolsTypeMap.put("SIP", 50);
+        protocolsTypeMap.put("SMB", 40);
+        protocolsTypeMap.put("TELNET", 0);
+    }
+
+    /**
+     * Create an entry for this application in the system account list, if it isn't already there.
+     *
+     * @param context Context
+     */
+    public static void CreateSyncAccount(Context context) {
+        boolean newAccount = false;
+        boolean setupComplete = PreferenceManager
+                .getDefaultSharedPreferences(context).getBoolean(PREF_SETUP_COMPLETE, false);
+
+        // Create account, if it's missing. (Either first run, or user has deleted account.)
+        Account account = HostageAccountService.GetAccount();
+        AccountManager accountManager = (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE);
+        if (accountManager.addAccountExplicitly(account, null, null)) {
+            // Inform the system that this account supports sync
+            ContentResolver.setIsSyncable(account, CONTENT_AUTHORITY, 1);
+            // Inform the system that this account is eligible for auto sync when the network is up
+            ContentResolver.setSyncAutomatically(account, CONTENT_AUTHORITY, true);
+            // Recommend a schedule for automatic synchronization. The system may modify this based
+            // on other scheduled syncs and network utilization.
+            ContentResolver.addPeriodicSync(
+                    account, CONTENT_AUTHORITY, new Bundle(),SYNC_FREQUENCY);
+            newAccount = true;
+        }
+
+        // Schedule an initial sync if we detect problems with either our account or our local
+        // data has been deleted. (Note that it's possible to clear app data WITHOUT affecting
+        // the account list, so wee need to check both.)
+        if (newAccount || !setupComplete) {
+            TriggerRefresh();
+            PreferenceManager.getDefaultSharedPreferences(context).edit()
+                    .putBoolean(PREF_SETUP_COMPLETE, true).commit();
+        }
+    }
+
+    public static void TriggerRefresh() {
+        Bundle b = new Bundle();
+        // Disable sync backoff and ignore sync preferences. In other words...perform sync NOW!
+        b.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
+        b.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
+        ContentResolver.requestSync(
+                HostageAccountService.GetAccount(),      // Sync account
+                CONTENT_AUTHORITY,                       // Content authority
+                b);                                      // Extras
+    }
+
+    public static void appendRecordToStringWriter(Record record, Writer stream){
+        try {
+            stream.append(
+            "{" +
+                "\"sensor\":{" +
+                    "\"name\":\"HosTaGe\"," +
+                    "\"type\":\"Honeypot\"" +
+                "}," +
+                "\"src\":{" +
+                    "\"ip\":\"" + record.getRemoteIP() + "\"," +
+                    "\"port\":" + record.getRemotePort() +
+                "}," +
+                "\"dst\":{" +
+                    "\"ip\":\"" + record.getExternalIP() /*record.getLocalIP()*/ + "\"," +
+                    "\"port\":" + record.getLocalPort() +
+                "}," +
+                "\"type\":" + (protocolsTypeMap.containsKey(record.getProtocol()) ? protocolsTypeMap.get(record.getProtocol()) : 0) + "," +
+                "\"log\":\"" + record.getProtocol() + "\"," +
+                "\"md5sum\":\"\"," +
+                "\"date\":" + (int)(record.getTimestamp() / 1000) +
+             "}\n"
+            );
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    public static boolean uploadRecordsToServer(String entity, String serverAddress){
+        HttpPost httppost;
+        try {
+            HttpClient httpClient = createHttpClient();
+            // Create HttpPost
+            httppost = new HttpPost(serverAddress);
+
+            StringEntity se = new StringEntity(entity);
+            httppost.addHeader("content-type", "application/json+newline");
+            httppost.setEntity(se);
+
+            // Execute HttpPost
+            HttpResponse response = httpClient.execute(httppost);
+
+            if(response.getStatusLine().getStatusCode() >= 400 && response.getStatusLine().getStatusCode() < 600){
+                return false;
+            }
+            Log.i("TracingSyncService", "Status Code: " + response.getStatusLine().getStatusCode());
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+        return true;
+    }
+
+    public static List<String[]> getCountriesFromServer(String serverAddress){
+        HttpGet httpget;
+        List<String[]> ret = new ArrayList<String[]>();
+
+        try {
+            HttpClient httpClient = createHttpClient();
+            // Create HttpPost
+            httpget = new HttpGet(serverAddress + "/get_countries");
+            httpget.addHeader("content-type", "application/json+newline");
+
+            // Execute HttpPost
+            HttpResponse response = httpClient.execute(httpget);
+
+            if(response.getStatusLine().getStatusCode() >= 400 && response.getStatusLine().getStatusCode() < 600){
+                return null;
+            }
+
+            BufferedReader bReader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
+            String line;
+            StringBuilder builder = new StringBuilder();
+            while ((line = bReader.readLine()) != null) {
+                builder.append(line);
+            }
+
+            JSONArray array = new JSONArray(builder.toString());
+            for(int i = 0; i < array.length(); i++){
+                JSONObject ob = array.getJSONObject(i);
+                ret.add(new String[]{ob.getString("cc"), ob.getString("country")});
+            }
+
+            Log.i("TracingSyncService", "Status Code: " + response.getStatusLine().getStatusCode());
+            return ret;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    public static HttpClient createHttpClient() {
+        try {
+            KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
+            trustStore.load(null, null);
+
+            SSLSocketFactory sf = new MySSLSocketFactory(trustStore);
+            sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
+
+            HttpParams params = new BasicHttpParams();
+            HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
+            HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
+
+            SchemeRegistry registry = new SchemeRegistry();
+            registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
+            registry.register(new Scheme("https", sf, 443));
+
+            ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);
+
+            return new DefaultHttpClient(ccm, params);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return new DefaultHttpClient();
+        }
+    }
+}

+ 2 - 2
src/de/tudarmstadt/informatik/hostage/sync/p2p/P2PSyncActivity.java

@@ -88,9 +88,9 @@ public class P2PSyncActivity extends Activity implements WifiP2pManager.GroupInf
         //mTxtP2PHeader = (TextView) findViewById(R.id.txtP2PHeader);
         //mTxtP2PSubHeader = (TextView) findViewById(R.id.txtP2PSubheader);
         //mTxtP2PHelpBack = (TextView) findViewById(R.id.txtP2PHelpBack);
-        mViewAnimator = (ViewAnimator) findViewById(R.id.viewAnimator);
+        //mViewAnimator = (ViewAnimator) findViewById(R.id.viewAnimator);
         mDevicesContainer = (RelativeLayout) findViewById(R.id.devicesContainer);
-        mWelcomeContainer = (RelativeLayout) findViewById(R.id.welcomeContainer);
+        //mWelcomeContainer = (RelativeLayout) findViewById(R.id.welcomeContainer);
         mTxtP2PSearchProgress = (TextView) findViewById(R.id.txtP2PSearchProgress);
         mLstP2PDevices = (ListView) findViewById(R.id.lstP2PDevices);
         //mBtnP2PSearch = (Button) findViewById(R.id.btnP2PSearch);

+ 52 - 85
src/de/tudarmstadt/informatik/hostage/sync/tracing/TracingSyncService.java

@@ -3,11 +3,16 @@ package de.tudarmstadt.informatik.hostage.sync.tracing;
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStreamReader;
+import java.io.OutputStream;
 import java.io.OutputStreamWriter;
+import java.io.StringWriter;
+import java.io.Writer;
 import java.net.HttpURLConnection;
 import java.net.URL;
 import java.security.KeyStore;
 import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
 
 import org.apache.http.HttpResponse;
 import org.apache.http.HttpVersion;
@@ -37,9 +42,12 @@ import android.os.ResultReceiver;
 import android.preference.PreferenceManager;
 import android.util.Log;
 import de.tudarmstadt.informatik.hostage.logging.NetworkRecord;
+import de.tudarmstadt.informatik.hostage.logging.Record;
 import de.tudarmstadt.informatik.hostage.logging.SyncInfoRecord;
 import de.tudarmstadt.informatik.hostage.net.MySSLSocketFactory;
 import de.tudarmstadt.informatik.hostage.persistence.HostageDBOpenHelper;
+import de.tudarmstadt.informatik.hostage.sync.android.SyncUtils;
+import de.tudarmstadt.informatik.hostage.ui.model.LogFilter;
 
 /**
  * Service that synchronizes with a specified remote server.
@@ -58,6 +66,7 @@ public class TracingSyncService extends IntentService {
 
 	public static final int RECORD_UPLOADED = 0x00;
 	public static final int SYNC_COMPLETE = 0x01;
+    public static final int SYNC_ERROR = 0x02;
 
 	private HttpClient httpClient;
 	private ResultReceiver receiver;
@@ -105,65 +114,55 @@ public class TracingSyncService extends IntentService {
 	 * Uploads all new Records to a server, specified in the settings.
 	 */
 	private void syncNewRecords() {
-		int lastUploadedAttackId = pref.getInt("LAST_UPLOADED_ATTACK_ID", -1);
-		// String serverAddress = pref.getString("pref_upload",
-		// "https://ssi.cased.de");
-		String serverAddress = "http://87.230.23.240/hostage/push.php";
-		ArrayList<NetworkRecord> recordList = dbh.getNetworkInformation();
+        long lastSyncTime = pref.getLong("LAST_SYNC_TIME", 0);
 
-		int size = recordList.size();
-		int offset = 1;
-		for (NetworkRecord record : recordList) {
-			boolean success = uploadSingleRecord(record, serverAddress);
-			Log.i("Tracing upload", "Upload of record: " + offset + "/" + size + ((success) ? " successful." : " failed."));
-			if (receiver != null) {
-				Bundle data = new Bundle();
-				data.putInt(UPLOAD_SIZE, size);
-				data.putInt(UPLOAD_PROGRESS, offset);
-				receiver.send(RECORD_UPLOADED, data);
-			}
-			offset++;
+		String serverAddress = pref.getString("pref_upload_server", "https://ssi.cased.de"); //"https://192.168.1.118:9999"
 
-			// TODO pull
-			// getRemoteData(record.getBssid(), record.getTimestamp());
-		}
-	}
+        LogFilter filter = new LogFilter();
+        filter.setAboveTimestamp(lastSyncTime);
 
-	/**
-	 * Uploads a single Record to a server, specified in the settings.
-	 * 
-	 * @param record
-	 *            The Record to upload.
-	 * @serverAddress Address of the target server
-	 * @return True if the upload was successful, else false.
-	 */
-	private boolean uploadSingleRecord(NetworkRecord record, String serverAddress) {
-		// Create a https client. Uses MySSLSocketFactory to accept all
-		// certificates
-		HttpPost httppost;
-		try {
-			httpClient = createHttpClient();
-			// Create HttpPost
-			httppost = new HttpPost(serverAddress);
-			// Create JSON String of Record
-			// TODO StringEntity se = new
-			// StringEntity(record.toString(TraCINgFormatter.getInstance()));
-			String s = record.toJSON();
-			StringEntity se = new StringEntity("record=" + record.toJSON());
-			httppost.addHeader("content-type", "application/x-www-form-urlencoded");
-			httppost.setEntity(se);
-			// Execute HttpPost
-			HttpResponse response = httpClient.execute(httppost);
-            // TODO Does it make sense to update the network record after a commit?
-			getRemoteData(record.getBssid(), record.getTimestampLocation());
-			Log.i("TracingSyncService", "Status Code: " + response.getStatusLine().getStatusCode());
-		} catch (Exception e) {
-			e.printStackTrace();
-			return false;
+        ArrayList<Record> records = dbh.getRecordsForFilter(filter);
+        StringWriter writer = new StringWriter();
+
+		int size = records.size();
+		int offset = 1;
+        int currOffset = 1;
+
+        boolean error = false;
+		for (Record record : records) {
+            SyncUtils.appendRecordToStringWriter(record, writer);
+
+            if(currOffset == 5 || offset == size){
+                boolean success = SyncUtils.uploadRecordsToServer(writer.toString(), serverAddress);
+                Log.i("Tracing upload", "Upload of record: " + offset + "/" + size + ((success) ? " successful." : " failed."));
+
+                if(!success){
+                    if(receiver != null){
+                        receiver.send(SYNC_ERROR, null);
+                        error = true;
+                    }
+                    break;
+                }
+
+                if (receiver != null) {
+                    Bundle data = new Bundle();
+                    data.putInt(UPLOAD_SIZE, size);
+                    data.putInt(UPLOAD_PROGRESS, offset);
+                    receiver.send(RECORD_UPLOADED, data);
+                }
+
+                writer.getBuffer().setLength(0);
+                currOffset = 0;
+            }
+
+            offset++;
+            currOffset++;
 		}
-		return true;
+
+        if(!error) pref.edit().putLong("LAST_SYNC_TIME", System.currentTimeMillis()).apply();
 	}
 
+
 	/**
 	 * Gets the data from the server and updates the database.
 	 */
@@ -214,36 +213,4 @@ public class TracingSyncService extends IntentService {
 			e.printStackTrace();
 		}
 	}
-
-	/**
-	 * Creates a HttpClient with an own SSL Socket.
-	 * 
-	 * @return HttpsClient who accepts accepts all certificates.
-	 * @see MySSLSocketFactory
-	 */
-	private HttpClient createHttpClient() {
-		try {
-			KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
-			trustStore.load(null, null);
-
-			SSLSocketFactory sf = new MySSLSocketFactory(trustStore);
-			sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
-
-			HttpParams params = new BasicHttpParams();
-			HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
-			HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
-
-			SchemeRegistry registry = new SchemeRegistry();
-			registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
-			registry.register(new Scheme("https", sf, 443));
-
-			ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);
-
-			return new DefaultHttpClient(ccm, params);
-		} catch (Exception e) {
-			e.printStackTrace();
-			return new DefaultHttpClient();
-		}
-	}
-
 }

+ 86 - 0
src/de/tudarmstadt/informatik/hostage/sync/wifi_direct/BackgroundTask.java

@@ -0,0 +1,86 @@
+package de.tudarmstadt.informatik.hostage.sync.wifi_direct;
+
+import android.os.AsyncTask;
+
+
+/**
+ * Created by Julien on 07.01.2015.
+ */
+public class BackgroundTask extends AsyncTask<Void, Void, String> {
+
+    /**
+     * This listener calls didSucceed if the method performInBackground will return true, otherwise it calls didFail.
+     */
+    public interface BackgroundTaskCompletionListener {
+        public void didSucceed();
+        public void didFail();
+    }
+
+    private boolean isInterrupted;
+
+    private boolean wasSuccessfully;
+
+    public void interrupt(boolean b){
+        this.isInterrupted = b;
+    }
+
+    public boolean isInterrupted() {
+        return isInterrupted;
+    }
+
+    private BackgroundTaskCompletionListener completion_listener;
+
+    public BackgroundTask(BackgroundTaskCompletionListener l){
+        super();
+        this.completion_listener = l;
+    }
+
+    /**
+     * Interrupts the background process.
+     * @param isInterrupted
+     */
+    public void setInterrupted(boolean isInterrupted) {
+        this.isInterrupted = isInterrupted;
+    }
+
+
+    /**
+     * Do any stuff here if it should run in the background. It should return true or false if the process was successfully.
+     * @return boolean
+     */
+    public boolean performInBackground(){
+        return true;
+    }
+
+    @Override
+    protected String doInBackground(Void... params) {
+        this.wasSuccessfully = this.performInBackground();
+        return null;
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see android.os.AsyncTask#onPostExecute(java.lang.Object)
+     */
+    @Override
+    protected void onPostExecute(String result) {
+        if (this.completion_listener != null) {
+            if (this.wasSuccessfully) {
+                this.completion_listener.didSucceed();
+            }else {
+                this.completion_listener.didFail();
+            }
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see android.os.AsyncTask#onPreExecute()
+     */
+    @Override
+    protected void onPreExecute() {
+
+
+    }
+
+}

+ 293 - 0
src/de/tudarmstadt/informatik/hostage/sync/wifi_direct/WiFiP2pBroadcastReceiver.java

@@ -0,0 +1,293 @@
+package de.tudarmstadt.informatik.hostage.sync.wifi_direct;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.net.NetworkInfo;
+import android.net.wifi.WpsInfo;
+import android.net.wifi.p2p.WifiP2pConfig;
+import android.net.wifi.p2p.WifiP2pDevice;
+import android.net.wifi.p2p.WifiP2pDeviceList;
+import android.net.wifi.p2p.WifiP2pInfo;
+import android.net.wifi.p2p.WifiP2pManager;
+import android.util.Log;
+
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by Julien on 07.01.2015.
+ */
+public class WiFiP2pBroadcastReceiver extends BroadcastReceiver implements WifiP2pManager.PeerListListener, WifiP2pManager.ConnectionInfoListener {
+
+
+    /**
+     * This listener will inform about any wifi direct change.
+     */
+    public interface WiFiP2pBroadcastListener {
+        public void discoveredDevices(List<WifiP2pDevice> peers);
+        public void wifiP2pIsEnabled(boolean enabled);
+        public void didConnect(boolean isHost, WifiP2pInfo connectionInfo);
+        public void failedToConnect();
+        public void didDisconnect();
+        public void failedToDisconnect();
+        public void ownDeviceInformationIsUpdated(WifiP2pDevice device);
+    }
+
+    private WifiP2pManager manager;
+    private WifiP2pManager.Channel channel;
+
+    private WifiP2pDevice ownDevice;
+
+    private android.net.NetworkInfo.DetailedState networkState = null;
+
+    static boolean setIsWifiP2pEnabled;
+
+    static boolean isConnected = false;
+
+    private WiFiP2pBroadcastListener eventListener;
+
+    /**
+     * @param manager WifiP2pManager system service
+     * @param channel Wifi p2p channel
+     * @param listener WiFiP2pBroadcastListener
+     */
+    public WiFiP2pBroadcastReceiver(WifiP2pManager manager,
+                                    WifiP2pManager.Channel channel,
+                                    WiFiP2pBroadcastListener listener) {
+        super();
+        this.manager = manager;
+        this.channel = channel;
+        this.eventListener = listener;
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see android.content.BroadcastReceiver#onReceive(android.content.Context,
+     * android.content.Intent)
+     */
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        String action = intent.getAction();
+        if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
+
+            // UI update to indicate wifi p2p status.
+            int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
+            if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
+                // Wifi Direct mode is enabled
+                setIsWifiP2pEnabled = (true);
+            } else {
+                setIsWifiP2pEnabled =(false);
+            }
+            this.eventListener.wifiP2pIsEnabled(setIsWifiP2pEnabled);
+
+        } else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
+            // THE DEVICE LIST CHANGED
+            // REQUEST THE LIST OF DEVICES
+            Log.d("WiFiP2pBroadcastReceiver", "P2P peers changed.");
+            if (manager != null) {
+                manager.requestPeers(channel, this);
+            }
+        } else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
+
+            if (manager == null) {
+                return;
+            }
+
+            NetworkInfo networkInfo = (NetworkInfo) intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);
+
+            if (networkInfo.isConnected()) {
+                isConnected = true;
+                // we are connected with the other device, request connection
+                // info to find group owner IP
+                manager.requestConnectionInfo(channel, this);
+                if (this.ownDevice == null){
+                    this.disconnect();
+                }
+            } else {
+                if (networkInfo.getDetailedState() == android.net.NetworkInfo.DetailedState.DISCONNECTED){
+                    isConnected = false;
+                }
+                if (this.networkState != null && !this.networkState.equals(networkInfo.getDetailedState()) && networkInfo.getDetailedState() == android.net.NetworkInfo.DetailedState.DISCONNECTED){
+                    // It's a disconnect
+                    this.eventListener.didDisconnect();
+                }
+            }
+            if (this.networkState != networkInfo.getDetailedState()){
+                Log.d("WiFiP2pBroadcastReceiver", "P2P device network state changed to " + this.getDeviceNetworkStatus(networkInfo.getDetailedState()) + ".");
+            }
+            this.networkState = networkInfo.getDetailedState();
+        } else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {
+            WifiP2pDevice device = intent.getParcelableExtra( WifiP2pManager.EXTRA_WIFI_P2P_DEVICE);
+            this.ownDevice = device;
+            this.eventListener.ownDeviceInformationIsUpdated(device);
+        }
+    }
+
+
+    // CONNECTION TO A DEVICE
+    // ConnectionInfoListener
+    @Override
+    public void onConnectionInfoAvailable(final WifiP2pInfo info) {
+
+        //
+        // The owner IP is now known.
+        //boolean thisDeviceIsHost = info.isGroupOwner;
+        // InetAddress from WifiP2pInfo struct.
+        //String ownerIP = info.groupOwnerAddress.getHostAddress();
+
+        // After the group negotiation, we assign the group owner as the file
+        // server. The file server is single threaded, single connection server
+        // socket.
+
+        if (info.groupFormed){
+            this.eventListener.didConnect(info.isGroupOwner, info);
+        }
+    }
+
+    // AVAILABLE DEVICES
+    // PEERLISTLISTENER
+    @Override
+    public void onPeersAvailable(WifiP2pDeviceList peerList) {
+
+        List<WifiP2pDevice> peers = new ArrayList<WifiP2pDevice>();
+        peers.addAll(peerList.getDeviceList());
+
+        if (peers.size() == 0) {
+            Log.d("WiFiP2pBroadcastReceiver", "No devices found");
+        }
+
+        this.eventListener.discoveredDevices(peers);
+        // DISMISS PROGRESS IF NEEDED
+    }
+
+    /**
+     * Connects to the given device.
+     * @param device
+     */
+    public void connect(WifiP2pDevice device){
+        if (device != null) {
+            WifiP2pConfig config = new WifiP2pConfig();
+            config.deviceAddress = device.deviceAddress;
+            config.wps.setup = WpsInfo.PBC;
+            manager.connect(channel, config, new WifiP2pManager.ActionListener() {
+                private WiFiP2pBroadcastListener eventListener;
+                @Override
+                public void onSuccess() {
+                    isConnected = true;
+                    // WiFiDirectBroadcastReceiver will notify us. Ignore for now.
+                }
+
+                @Override
+                public void onFailure(int reason) {
+                    this.eventListener.failedToConnect();
+                }
+
+                public WifiP2pManager.ActionListener init(WiFiP2pBroadcastListener eventListener){
+                    this.eventListener = eventListener;
+                    return this;
+                }
+            }.init(this.eventListener));
+        }
+    }
+
+    /**
+     * Disconnects from the connected wifi direct group if the own device is still connected.
+     */
+    public void disconnect() {
+        if (isConnected){
+            manager.removeGroup(channel, new WifiP2pManager.ActionListener() {
+                private WiFiP2pBroadcastListener eventListener;
+
+                @Override
+                public void onFailure(int reasonCode) {
+                    this.eventListener.failedToDisconnect();
+                }
+
+                @Override
+                public void onSuccess() {
+                    isConnected = false;
+                    this.eventListener.didDisconnect();
+                }
+
+                public WifiP2pManager.ActionListener init(WiFiP2pBroadcastListener eventListener){
+                    this.eventListener = eventListener;
+                    return this;
+                }
+            }.init(this.eventListener));
+        }
+    }
+
+    /**
+     * Discover other devices.
+     * The WiFiP2pBroadcastListener will inform about any change.
+     */
+    public void discoverDevices(){
+        manager.discoverPeers(channel, new WifiP2pManager.ActionListener() {
+            @Override
+            public void onSuccess() {
+                Log.d("WiFiP2pBroadcastReceiver", " Discovering Peers initiated.");
+            }
+            @Override
+            public void onFailure(int reasonCode) {
+                Log.d("WiFiP2pBroadcastReceiver", " Discovering Peers failed. c="+reasonCode);
+            }
+        });
+    }
+
+    /**
+     * Returns a string representation of the given network status.
+     * @param networkStatus network status
+     * @return localised network status string
+     */
+    private String getDeviceNetworkStatus(android.net.NetworkInfo.DetailedState networkStatus) {
+        switch (networkStatus) {
+            case DISCONNECTED: {
+                return "Disconnected";
+            }
+            case AUTHENTICATING:
+            {
+                return "Authenticating";
+            }
+            case BLOCKED:
+            {
+                return "Blocked";
+            }
+            case CONNECTED: {
+                return "CONNECTED";
+            }
+            case CONNECTING:
+            {
+                return "Connecting";
+            }
+            case DISCONNECTING:
+            {
+                return "Disconnecting";
+            }
+            case FAILED:
+            {
+                return "Failed";
+            }
+            case IDLE:
+            {
+                return "IDLE";
+            }
+            case OBTAINING_IPADDR:
+            {
+                return "Obtaining IPADDR";
+            }
+            case SCANNING:
+            {
+                return "Scanning";
+            }
+            case SUSPENDED:
+            {
+                return "Suspended";
+            }
+            default: {
+                return "Unknown";
+            }
+        }
+    }
+}

+ 167 - 0
src/de/tudarmstadt/informatik/hostage/sync/wifi_direct/WiFiP2pClientTask.java

@@ -0,0 +1,167 @@
+package de.tudarmstadt.informatik.hostage.sync.wifi_direct;
+
+import android.net.wifi.p2p.WifiP2pDevice;
+import android.net.wifi.p2p.WifiP2pManager;
+import android.util.Log;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+
+/**
+ * Created by Julien on 07.01.2015.
+ *
+ * The client task.
+ *
+ * The client is the initial actor and will try to connect to the host as long as the task is not interrupted or successfully connected to the host.
+ *
+ *
+ */
+public abstract class WiFiP2pClientTask extends BackgroundTask {
+
+    // Set the port here for the client and host task.
+    public static int DEFAULT_WIFI_PORT = 1029;
+
+    private String hostIP;
+    private Socket socket;
+
+    private WifiP2pDevice ownDevice;
+
+    public String getHostIP() {
+        return hostIP;
+    }
+
+    public void setHostIP(String hostIP) {
+        this.hostIP = hostIP;
+    }
+
+
+    public static int port(){
+        return DEFAULT_WIFI_PORT;
+    }
+    public static int time_out(){
+        return 1000;
+    }
+
+
+    public WiFiP2pClientTask(String hostIP, WifiP2pDevice ownDevice, BackgroundTaskCompletionListener l){
+        super(l);
+        this.ownDevice = ownDevice;
+        this.hostIP = hostIP;
+    }
+
+
+    @Override
+    public void interrupt(boolean b){
+        super.interrupt(b);
+        if (b && this.socket != null) {
+            try {
+                this.socket.close();
+            } catch (IOException e) {
+                Log.e("WiFiP2pClientTask", e.getMessage());
+            }
+        }
+    }
+
+    @Override
+    public boolean performInBackground(){
+        int tryNum = 1;
+        int max_tries = 10;
+        while (!this.isInterrupted() && tryNum <= max_tries){
+            this.socket = new Socket();
+
+            try {
+                Log.d("WiFiP2pClientTask", "Opening client socket - ");
+                socket.bind(null);
+                socket.connect((new InetSocketAddress(hostIP, port())), time_out());
+
+                Log.d("WiFiP2pClientTask", "Client socket - " + socket.isConnected());
+                this.handleConnection(socket);
+
+                Log.d("WiFiP2pClientTask", "Client: Data written");
+            } catch (ClassNotFoundException e){
+                Log.e("WiFiP2pClientTask", e.getMessage());
+                return false;
+            } catch (IOException e) {
+                Log.e("WiFiP2pClientTask", e.getMessage());
+
+                if(this.isInterrupted()) {
+                    this.interrupt(true);
+                    break;
+                }
+
+                long seconds_to_wait = (long) Math.min(60, Math.pow(2, 1));
+                tryNum++;
+                Log.i("WiFiP2pClientTask", "could not connect to server. Will try again in " + seconds_to_wait + "s");
+                try {
+                    Thread.sleep(seconds_to_wait * time_out());
+                } catch (InterruptedException ie){
+                    ie.printStackTrace();
+                }
+            } finally {
+                if (socket != null) {
+                    if (socket.isConnected()) {
+                        try {
+                            socket.close();
+                        } catch (IOException e) {
+                            // Give up
+                            e.printStackTrace();
+                            Log.d("WiFiP2p_Error"," Failed to close socket - "+ e.getLocalizedMessage());
+                            return false;
+                        }
+                    }
+                }
+            }
+        }
+        return tryNum <= max_tries;
+    }
+
+
+    /**
+     * Initiates the client task and sends the first response to the host.
+     * @param client the client socket
+     * @throws IOException
+     * @throws ClassNotFoundException
+     */
+    private void handleConnection(Socket client) throws IOException, ClassNotFoundException {
+
+        InputStream is = client.getInputStream();
+        ObjectInputStream ois = new ObjectInputStream(is);
+        OutputStream os = client.getOutputStream();
+        ObjectOutputStream oos = new ObjectOutputStream(os);
+
+        Object obj = null;
+
+        do {
+            WiFiP2pSerializableObject receivedObj = (  WiFiP2pSerializableObject) obj;
+            obj = null;
+            WiFiP2pSerializableObject toSend = this.handleReceivedObject(receivedObj);
+            if (toSend != null) {
+                toSend.setActingDevice_IP_address(this.ownDevice.deviceAddress);
+                oos.writeObject(toSend);
+                oos.flush();
+                oos.reset();
+                obj = ois.readObject();
+            }
+        } while (obj != null && obj instanceof WiFiP2pSerializableObject);
+
+        oos.close();
+        os.close();
+        ois.close();
+        is.close();
+
+        this.interrupt(true);
+    }
+
+    /**
+     * This method is initially called with a null parameter to inform about a initial state.
+     * Return null to disable the client task.
+     * @param receivedObj the response for the last request, null if it is the first call on the host.
+     * @return WiFiP2pSerializableObject request object
+     */
+    public abstract WiFiP2pSerializableObject handleReceivedObject(WiFiP2pSerializableObject receivedObj);
+}

+ 111 - 0
src/de/tudarmstadt/informatik/hostage/sync/wifi_direct/WiFiP2pEventHandler.java

@@ -0,0 +1,111 @@
+package de.tudarmstadt.informatik.hostage.sync.wifi_direct;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.IntentFilter;
+import android.net.wifi.WifiManager;
+import android.net.wifi.p2p.WifiP2pDevice;
+import android.net.wifi.p2p.WifiP2pManager;
+
+/**
+ * Created by Julien on 07.01.2015.
+ */
+public class WiFiP2pEventHandler implements WifiP2pManager.ChannelListener {
+
+    /**
+     * The WiFiP2pEventListener informs about all wifi direct changes.
+     */
+    public interface WiFiP2pEventListener extends WiFiP2pBroadcastReceiver.WiFiP2pBroadcastListener{
+         public void onConnectionLost();
+    }
+
+    private WifiP2pManager manager;
+
+    private boolean retryChannel = false;
+
+    private final IntentFilter intentFilter = new IntentFilter();
+    private WifiP2pManager.Channel channel;
+    private WiFiP2pBroadcastReceiver receiver = null;
+
+    private WiFiP2pEventListener eventListener;
+
+    private Activity activity;
+
+
+    public WiFiP2pEventHandler(Activity activity, WiFiP2pEventListener listener){
+        this.eventListener = listener;
+        this.activity = activity;
+        intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
+        intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
+        intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
+        intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
+
+        manager = (WifiP2pManager) activity.getSystemService(Context.WIFI_P2P_SERVICE);
+        channel = manager.initialize(activity, activity.getMainLooper(), this);
+    }
+
+    public void setOnRetryIfTheChannelIsLost(boolean shouldRetry){
+        this.retryChannel = shouldRetry;
+    }
+    public boolean isRetryingIfTheChannelIsLost(){
+        return this.retryChannel;
+    }
+
+    /**
+     * Call this method if the app comes back to foreground. E.g. in the onResume from the activity.
+     */
+    public void startService() {
+        if (receiver == null){
+            receiver = new WiFiP2pBroadcastReceiver(manager, channel, this.eventListener);
+            activity.registerReceiver(receiver, intentFilter);
+        }
+    }
+
+    /**
+     * Call this method to disabled wifi direct while the app is in the background.  E.g. in the onPause from the activity.
+     */
+    public void stopService() {
+        if (receiver != null) {
+            activity.unregisterReceiver(receiver);
+            receiver = null;
+        }
+    }
+
+    @Override
+    public void onChannelDisconnected() {
+        // we will try once more
+        if (manager != null && !retryChannel) {
+            retryChannel = true;
+            manager.initialize(this.activity, this.activity.getMainLooper(), this);
+            receiver = new WiFiP2pBroadcastReceiver(manager, channel, this.eventListener);
+            activity.registerReceiver(receiver, intentFilter);
+        } else {
+            this.eventListener.onConnectionLost();
+        }
+    }
+
+    /**
+     * Connect your device to the given device.
+     * @param device
+     */
+    public void connect(WifiP2pDevice device){
+        if (this.receiver != null && device != null)
+            this.receiver.connect(device);
+    }
+
+    /**
+     * Disconnect from the connected wifi group.
+     */
+    public void disconnect() {
+        if (this.receiver != null)
+            this.receiver.disconnect();
+    }
+
+    /**
+     * Discover all available wifi direct device in the current environment.
+     */
+    public void discoverDevices(){
+        if (this.receiver != null)
+            this.receiver.discoverDevices();
+    }
+}

+ 42 - 0
src/de/tudarmstadt/informatik/hostage/sync/wifi_direct/WiFiP2pSerializableObject.java

@@ -0,0 +1,42 @@
+package de.tudarmstadt.informatik.hostage.sync.wifi_direct;
+
+import java.io.Serializable;
+
+/**
+ * Created by Julien on 07.01.2015.
+ *
+ * An instance of this class is send from client to host and another one will be send back as response.
+ * You can create subclass for any variation. Any information will be transferred.
+ *
+ */
+public class WiFiP2pSerializableObject implements Serializable {
+
+    private String requestIdentifier;
+    private String actingDevice_IP_address;
+
+
+    public Serializable getObjectToSend() {
+        return objectToSend;
+    }
+
+    public void setObjectToSend(Serializable objectToSend) {
+        this.objectToSend = objectToSend;
+    }
+
+    private Serializable objectToSend;
+
+    public void setRequestIdentifier(String m){
+        this.requestIdentifier = m;
+    }
+    public String getRequestIdentifier(){
+        return this.requestIdentifier;
+    }
+
+    public String getActingDevice_IP_address() {
+        return actingDevice_IP_address;
+    }
+
+    public void setActingDevice_IP_address(String actingDevice_IP_address) {
+        this.actingDevice_IP_address = actingDevice_IP_address;
+    }
+}

+ 131 - 0
src/de/tudarmstadt/informatik/hostage/sync/wifi_direct/WiFiP2pServerTask.java

@@ -0,0 +1,131 @@
+package de.tudarmstadt.informatik.hostage.sync.wifi_direct;
+
+import android.net.wifi.p2p.WifiP2pDevice;
+import android.net.wifi.p2p.WifiP2pManager;
+import android.util.Log;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.net.ServerSocket;
+import java.net.Socket;
+
+/**
+ * Created by Julien on 07.01.2015.
+ *
+ * The Server Task.
+ *
+ * The Server task is waiting as long as a client is connecting to it.
+ * As a result of this the main part and process will start after the client had send the first data.
+ *
+ * You never know how will become the host / server.
+ * So you need to implement a strategy if you want do send just from one specific device to the other.
+ *
+ *  * The server creates the object stream before the client can do it - to avoid a chicken and egg problem.
+ */
+public abstract class WiFiP2pServerTask extends BackgroundTask {
+
+
+    private ServerSocket serverSocket;
+
+    private WifiP2pDevice ownDevice;
+
+
+    @Override
+    public void interrupt(boolean b){
+        super.interrupt(b);
+        if (b && this.serverSocket != null) {
+            try {
+                this.serverSocket.close();
+            } catch (IOException e) {
+                Log.e("WiFiP2pServerTask", e.getMessage());
+            }
+        }
+    }
+
+    public WiFiP2pServerTask( WifiP2pDevice ownDevice, BackgroundTaskCompletionListener l){
+        super(l);
+        this.ownDevice = ownDevice;
+    }
+
+    @Override
+    public boolean performInBackground(){
+        while (!this.isInterrupted()){
+            try {
+                this.serverSocket = new ServerSocket(WiFiP2pClientTask.port());
+                Log.d("WiFiP2pServerTask", "Server: Socket opened");
+                Socket client = this.serverSocket.accept();
+                Log.d("WiFiP2pServerTask", "Server: connection done");
+
+                this.handleConnection(client, this.serverSocket);
+
+                client.close();
+                serverSocket.close();
+
+                return true;
+            } catch (ClassNotFoundException e){
+                e.printStackTrace();
+                Log.e("WiFiP2pServerTask", e.getMessage());
+                return false;
+            } catch (IOException  e) {
+                e.printStackTrace();
+                Log.e("WiFiP2pServerTask", e.getMessage());
+                return false;
+            }
+        }
+        return true;
+    }
+
+
+    /**
+     * The server creates the object stream before the client can do it to avoid a chicken and egg problem.
+     * @param client the client socket.
+     * @param server the server socket.
+     * @throws IOException
+     * @throws ClassNotFoundException
+     */
+    private void handleConnection(Socket client, ServerSocket server) throws IOException, ClassNotFoundException {
+        OutputStream os = client.getOutputStream();
+        ObjectOutputStream oos = new ObjectOutputStream(os);
+        oos.flush();
+
+        InputStream is = client.getInputStream();
+        ObjectInputStream ois = new ObjectInputStream(is);
+
+
+        Object obj = ois.readObject();
+
+        while (obj != null && obj instanceof WiFiP2pSerializableObject) {
+            WiFiP2pSerializableObject receivedObj = (  WiFiP2pSerializableObject) obj;
+            obj = null;
+            WiFiP2pSerializableObject toSend = this.handleReceivedObject(receivedObj);
+            if (toSend != null) {
+                toSend.setActingDevice_IP_address(this.ownDevice.deviceAddress);
+                oos.writeObject(toSend);
+                oos.flush();
+                oos.reset();
+            }
+            try {
+                obj = ois.readObject();
+            }catch (IOException e){
+                // IF NULL WAS TRANSMITTED
+                obj = null;
+            }
+        }
+
+        oos.close();
+        os.close();
+        ois.close();
+        is.close();
+    }
+
+    /**
+     * This method will be called if the server receives data from the client.
+     * Always return a WiFiP2pSerializableObject instance to give a simple response, otherwise the connection will be disconnected.
+     * @param receivedObj WiFiP2pSerializableObject the clients request
+     * @return WiFiP2pSerializableObject the response
+     */
+    abstract public WiFiP2pSerializableObject handleReceivedObject(WiFiP2pSerializableObject receivedObj);
+}

+ 75 - 0
src/de/tudarmstadt/informatik/hostage/sync/wifi_direct/sync_tasks/SyncClientTask.java

@@ -0,0 +1,75 @@
+package de.tudarmstadt.informatik.hostage.sync.wifi_direct.sync_tasks;
+
+import android.content.Context;
+import android.net.wifi.p2p.WifiP2pDevice;
+import android.net.wifi.p2p.WifiP2pManager;
+import android.util.Log;
+
+import de.tudarmstadt.informatik.hostage.logging.SyncData;
+import de.tudarmstadt.informatik.hostage.logging.SyncInfo;
+import de.tudarmstadt.informatik.hostage.persistence.HostageDBOpenHelper;
+import de.tudarmstadt.informatik.hostage.sync.Synchronizer;
+import de.tudarmstadt.informatik.hostage.sync.wifi_direct.WiFiP2pClientTask;
+import de.tudarmstadt.informatik.hostage.sync.wifi_direct.WiFiP2pSerializableObject;
+
+
+
+/**
+ * Created by Julien on 14.01.2015.
+ */
+public class SyncClientTask extends WiFiP2pClientTask {
+
+    private HostageDBOpenHelper mdbh;
+    private Synchronizer synchronizer;
+
+    public SyncClientTask(String hostIP,  WifiP2pDevice ownDevice,BackgroundTaskCompletionListener l, Context context) {
+        super(hostIP, ownDevice, l);
+        mdbh = new HostageDBOpenHelper(context);
+        synchronizer = new Synchronizer(mdbh);
+    }
+
+    @Override
+    public WiFiP2pSerializableObject handleReceivedObject(WiFiP2pSerializableObject receivedObj) {
+
+        if (receivedObj == null) {
+            Log.i("WiFiP2p_Client", "Starting sync process: " + SyncHostTask.SYNC_INFO_REQUEST);
+            SyncInfo thisSyncInfo = synchronizer.getSyncInfo();
+            WiFiP2pSerializableObject syncObj = new WiFiP2pSerializableObject();
+
+            syncObj.setObjectToSend(thisSyncInfo);
+            syncObj.setRequestIdentifier(SyncHostTask.SYNC_INFO_REQUEST);
+
+            return syncObj;
+
+        } else {
+            Log.i("WiFiP2p_Client", "Received: " + receivedObj.getRequestIdentifier());
+            if (receivedObj.getRequestIdentifier().equals(SyncHostTask.SYNC_INFO_RESPONSE)) {
+                SyncInfo sinfo = (SyncInfo) receivedObj.getObjectToSend();
+
+                if (sinfo != null && (sinfo instanceof SyncInfo)) {
+                    Log.i("WiFiP2p_Client", "Sending Data: " + SyncHostTask.SYNC_DATA_REQUEST);
+                    SyncData syncData = synchronizer.getSyncData(sinfo);
+                    WiFiP2pSerializableObject syncObj = new WiFiP2pSerializableObject();
+
+                    syncObj.setObjectToSend(syncData);
+                    syncObj.setRequestIdentifier(SyncHostTask.SYNC_DATA_REQUEST);
+
+                    return syncObj;
+                }
+
+            } else if (receivedObj.getRequestIdentifier().equals(SyncHostTask.SYNC_DATA_RESPONSE)) {
+                Log.i("WiFiP2p_Client", "Received Sync Data - ending sync process successfully." );
+                SyncData sdata = (SyncData) receivedObj.getObjectToSend();
+
+                if (sdata != null && (sdata instanceof SyncData)) {
+                    synchronizer.updateFromSyncData(sdata);
+                }
+            }
+        }
+
+        // DISCONNECT
+        this.interrupt(true);
+
+        return null;
+    }
+}

+ 92 - 0
src/de/tudarmstadt/informatik/hostage/sync/wifi_direct/sync_tasks/SyncHostTask.java

@@ -0,0 +1,92 @@
+package de.tudarmstadt.informatik.hostage.sync.wifi_direct.sync_tasks;
+
+import android.content.Context;
+import android.net.wifi.p2p.WifiP2pDevice;
+import android.net.wifi.p2p.WifiP2pManager;
+import android.util.Log;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import de.tudarmstadt.informatik.hostage.logging.SyncData;
+import de.tudarmstadt.informatik.hostage.logging.SyncInfo;
+import de.tudarmstadt.informatik.hostage.persistence.HostageDBOpenHelper;
+import de.tudarmstadt.informatik.hostage.sync.Synchronizer;
+import de.tudarmstadt.informatik.hostage.sync.wifi_direct.WiFiP2pSerializableObject;
+import de.tudarmstadt.informatik.hostage.sync.wifi_direct.WiFiP2pServerTask;
+
+/**
+ * Created by Julien on 14.01.2015.
+ */
+public class SyncHostTask extends WiFiP2pServerTask {
+
+
+    public static final String SYNC_INFO_REQUEST = "sync_info_request";
+    public static final String SYNC_INFO_RESPONSE = "sync_info_response";
+
+    public static final String SYNC_DATA_REQUEST = "sync_data_request";
+    public static final String SYNC_DATA_RESPONSE = "sync_data_response";
+
+    private HostageDBOpenHelper mdbh;
+    private Synchronizer synchronizer;
+
+    private Map<String, SyncInfo> receivedInfoPerDevice;
+
+    public SyncHostTask(  WifiP2pDevice ownDevice, BackgroundTaskCompletionListener l , Context context) {
+        super(ownDevice , l);
+        mdbh = new HostageDBOpenHelper(context);
+        synchronizer = new Synchronizer(mdbh);
+
+        this.receivedInfoPerDevice = new HashMap<String, SyncInfo>();
+    }
+
+    @Override
+    public WiFiP2pSerializableObject handleReceivedObject(WiFiP2pSerializableObject receivedObj){
+        if (receivedObj != null) {
+            Log.i("WiFiP2p_Host", "Received: " + receivedObj.getRequestIdentifier());
+
+            if (receivedObj.getRequestIdentifier().equals(SYNC_INFO_REQUEST)){
+                Log.i("WiFiP2p_Host", "Sending Sync Info: " + SYNC_INFO_RESPONSE);
+
+                SyncInfo syncInfo = (SyncInfo) receivedObj.getObjectToSend();
+                this.receivedInfoPerDevice.put(receivedObj.getActingDevice_IP_address(), syncInfo);
+
+                SyncInfo response = synchronizer.getSyncInfo();
+                WiFiP2pSerializableObject syncObj = new WiFiP2pSerializableObject();
+
+                syncObj.setObjectToSend(response);
+                syncObj.setRequestIdentifier(SYNC_INFO_RESPONSE);
+
+                return syncObj;
+            }
+
+            if (receivedObj.getRequestIdentifier().equals(SYNC_DATA_REQUEST)){
+                Log.i("WiFiP2p_Host", "Sending Sync Data: " + SYNC_DATA_RESPONSE);
+
+                SyncData sdata = (SyncData) receivedObj.getObjectToSend();
+
+                if (sdata != null && sdata instanceof SyncData){
+                    synchronizer.updateFromSyncData(sdata);
+                }
+
+                SyncInfo syncInfo = this.receivedInfoPerDevice.get(receivedObj.getActingDevice_IP_address());
+                if (syncInfo != null){
+                    SyncData response = synchronizer.getSyncData(syncInfo);
+
+                    WiFiP2pSerializableObject syncObj = new WiFiP2pSerializableObject();
+                    syncObj.setObjectToSend(response);
+                    syncObj.setRequestIdentifier(SYNC_DATA_RESPONSE);
+
+                    return syncObj;
+                }
+            }
+        }
+
+        Log.i("WiFiP2p_Host", "Stop Sync Process - Performing a disconnect.");
+        // DISCONNECT
+        this.interrupt(true);
+        return null;
+    }
+}

+ 554 - 0
src/de/tudarmstadt/informatik/hostage/sync/wifi_direct/ui/WiFiP2pSyncActivity.java

@@ -0,0 +1,554 @@
+package de.tudarmstadt.informatik.hostage.sync.wifi_direct.ui;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.ProgressDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.net.wifi.p2p.WifiP2pDevice;
+import android.net.wifi.p2p.WifiP2pInfo;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+import android.widget.Toast;
+import android.widget.ViewAnimator;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import de.tudarmstadt.informatik.hostage.R;
+import de.tudarmstadt.informatik.hostage.sync.wifi_direct.BackgroundTask;
+import de.tudarmstadt.informatik.hostage.sync.wifi_direct.WiFiP2pEventHandler;
+import de.tudarmstadt.informatik.hostage.sync.wifi_direct.sync_tasks.SyncClientTask;
+import de.tudarmstadt.informatik.hostage.sync.wifi_direct.sync_tasks.SyncHostTask;
+import de.tudarmstadt.informatik.hostage.ui.activity.MainActivity;
+
+/**
+ * Created by Julien on 14.01.2015.
+ */
+public class WiFiP2pSyncActivity extends Activity implements AdapterView.OnItemClickListener {
+
+    public static String CONNECTION_LOST_MESSAGE = MainActivity.getContext().getString(R.string.CONNECTION_LOST_MESSAGE);// "Connection lost permanently, please enable wifi direct.";
+    public static String COULD_NOT_CONNECT_MESSAGE =MainActivity.getContext().getString(R.string.COULD_NOT_CONNECT_MESSAGE);// "Could not connect to device. Retry.";
+
+    public static String SYNCHRONIZATION_COMPLETE_MESSAGE =MainActivity.getContext().getString(R.string.SYNCHRONIZATION_COMPLETE_MESSAGE);// "Synchronization complete.";
+    public static String SYNCHRONIZATION_FAILED_MESSAGE =MainActivity.getContext().getString(R.string.SYNCHRONIZATION_FAILED_MESSAGE);// "Could not synchronize devices. Retry";
+
+    public static String PERFORMING_TASK_AS_HOST =MainActivity.getContext().getString(R.string.PERFORMING_TASK_AS_HOST);// "Acting as Host.";
+    public static String PERFORMING_TASK_AS_CLIENT = MainActivity.getContext().getString(R.string.PERFORMING_TASK_AS_CLIENT);//"Acting as Client.";
+
+    public static String ACTIONBAR_TITLE =MainActivity.getContext().getString(R.string.ACTIONBAR_TITLE);// "WifiDirect Synchronization";
+    public static String PROGRESS_TITLE_LOADING =MainActivity.getContext().getString(R.string.PROGRESS_TITLE_LOADING);// "Loading...";
+    public static String PROGRESS_TITLE_CONNECTING = MainActivity.getContext().getString(R.string.PROGRESS_TITLE_CONNECTING);//"Connecting...";
+
+    public static String DEVICE_STATUS_AVAILABLE =MainActivity.getContext().getString(R.string.DEVICE_STATUS_AVAILABLE);// "Available";
+    public static String DEVICE_STATUS_INVITED =MainActivity.getContext().getString(R.string.DEVICE_STATUS_INVITED);// "Invited";
+    public static String DEVICE_STATUS_CONNECTED = MainActivity.getContext().getString(R.string.DEVICE_STATUS_CONNECTED);//"Connected";
+    public static String DEVICE_STATUS_FAILED =MainActivity.getContext().getString(R.string.DEVICE_STATUS_FAILED);// "Failed";
+    public static String DEVICE_STATUS_UNAVAILABLE =MainActivity.getContext().getString(R.string.DEVICE_STATUS_UNAVAILABLE);// "Unavailable";
+    public static String DEVICE_STATUS_UNKNOWN =MainActivity.getContext().getString(R.string.DEVICE_STATUS_UNKNOWN);// "Unknown";
+
+    public static String WIFI_STATUS_DISABLED_MESSAGE =MainActivity.getContext().getString(R.string.WIFI_STATUS_DISABLED_MESSAGE);// "WiFi Direct down, please enable WiFi Direct";
+    public static String WIFI_STATUS_ENABLE_BUTTON = MainActivity.getContext().getString(R.string.WIFI_STATUS_ENABLE_BUTTON);//"Enable WiFi Direct";
+
+    public static String CANCEL_BUTTON_TITLE =MainActivity.getContext().getString(R.string.CANCEL_BUTTON_TITLE);// "Cancel";
+
+
+    private SyncClientTask clientTask;
+    private SyncHostTask  hostTask;
+    private BackgroundTask executingTask;
+    private boolean isHost;
+
+    private WiFiP2pEventHandler _wifiEventHandler = null;
+
+    private WiFiP2pEventHandler.WiFiP2pEventListener _p2pEventListener = null;
+    private BackgroundTask.BackgroundTaskCompletionListener _syncCompletionListener = null;
+
+
+    private TextView mTxtP2PDeviceName;
+    private TextView mTxtP2PDeviceStatus;
+    private ViewAnimator mViewAnimator;
+    private RelativeLayout mDevicesContainer;
+    private TextView mTxtP2PSearchProgress;
+    private ListView mLstP2PDevices;
+    private RelativeLayout mWelcomeContainer;
+    private TextView mTxtP2PNotAvailable;
+    private TextView mTxtP2PChangeDeviceName;
+
+    private WifiP2pDevice ownDevice;
+    private WifiP2pDevice mOtherDevice;
+
+    private ArrayList<WifiP2pDevice> discoveredDevices = new ArrayList<WifiP2pDevice>();
+
+    private ProgressDialog progressDialog;
+
+
+    public boolean isHost() {
+        return isHost;
+    }
+    public void setHost(boolean isHost) {
+        this.isHost = isHost;
+    }
+
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        this.wifiEventHandler();
+
+        setContentView(R.layout.activity_p2_psync);
+
+        assert getActionBar() != null;
+        getActionBar().setTitle(ACTIONBAR_TITLE);
+
+        this.extractFromView();
+        this.registerListeners();
+
+        this.wifiEventHandler().startService();
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        this.wifiEventHandler().startService();
+    }
+
+    @Override
+    public void onPause() {
+        if (this.clientTask != null) this.clientTask.interrupt(true);
+        if (this.hostTask != null) this.hostTask.interrupt(true);
+
+        this.wifiEventHandler().stopService();
+        super.onPause();
+    }
+
+    @Override
+    protected void onStart()
+    {
+        super.onStart();
+        this.wifiEventHandler().startService();
+    }
+
+    @Override
+    protected void onStop()
+    {
+        if (this.clientTask != null) this.clientTask.interrupt(true);
+        if (this.hostTask != null) this.hostTask.interrupt(true);
+        this.wifiEventHandler().disconnect();
+        this.wifiEventHandler().stopService();
+        super.onStop();
+    }
+
+    @Override
+    protected void onDestroy(){
+        if (this.clientTask != null) this.clientTask.interrupt(true);
+        if (this.hostTask != null) this.hostTask.interrupt(true);
+        this.wifiEventHandler().stopService();
+        super.onDestroy();
+    }
+
+    /**
+     * Returns a instance of the wifi event handler listener object. If no private instance was initiated it creates a new one.
+     * This object handles all gui changes.
+     * @return WiFiP2pEventHandler.WiFiP2pEventListener
+     */
+    private WiFiP2pEventHandler.WiFiP2pEventListener eventListener(){
+        if (_p2pEventListener == null){
+            _p2pEventListener = new WiFiP2pEventHandler.WiFiP2pEventListener() {
+                WiFiP2pSyncActivity activity = null;
+                public WiFiP2pEventHandler.WiFiP2pEventListener init(WiFiP2pSyncActivity act){
+                    this.activity = act;
+                    return this;
+                }
+
+                @Override
+                public void discoveredDevices(List<WifiP2pDevice> peers) {
+                    Log.d("WiFiP2pSyncActivity", "Actualise devices list" + ".");
+                    this.activity.updateDeviceListView(peers);
+                }
+
+                @Override
+                public void wifiP2pIsEnabled(boolean enabled) {
+                    String tmp = enabled? "enabled" : "disabled";
+                    Log.d("WiFiP2pSyncActivity", "Peer to peer is " + tmp + ".");
+                    this.activity.setWifiDirectAvailable(enabled);
+                }
+
+                @Override
+                public void didConnect(boolean isHost, WifiP2pInfo connectionInfo) {
+                    Log.d("WiFiP2pSyncActivity", "Did connect" + ".");
+
+                    String progressTitle = PROGRESS_TITLE_LOADING;
+                    if (this.activity.progressDialog != null){
+                        this.activity.progressDialog.dismiss();
+                    }
+                    this.activity.progressDialog = ProgressDialog.show(activity, "", progressTitle);
+
+
+                    this.activity.setHost(isHost);
+                    if (isHost){
+                        Log.d("WiFiP2pSyncActivity", "Connected as HOST" + ".");
+                        this.activity.startHost();
+                    } else {
+                        Log.d("WiFiP2pSyncActivity", "Connected as Client" + ".");
+                        this.activity.startClient(connectionInfo);
+                    }
+                }
+
+                @Override
+                public void failedToConnect() {
+                    Log.d("WiFiP2pSyncActivity", "Failed to connect" + ".");
+                    Toast.makeText(this.activity, COULD_NOT_CONNECT_MESSAGE , Toast.LENGTH_LONG).show();
+                    this.activity.progressDialog.dismiss();
+                }
+
+                @Override
+                public void didDisconnect() {
+                    Log.d("WiFiP2pSyncActivity", "Did disconnect" + ".");
+                    this.activity.progressDialog.dismiss();
+                }
+
+                @Override
+                public void failedToDisconnect() {
+                    Log.d("WiFiP2pSyncActivity", "Failed to disconnect" + ".");
+                    //Toast.makeText(this.activity, "Could not disconnect with device. Retry.", Toast.LENGTH_LONG).show();
+                    // Other device did disconnect a while before.
+                    this.activity.progressDialog.dismiss();
+                }
+
+                @Override
+                public void ownDeviceInformationIsUpdated(WifiP2pDevice device) {
+                    Log.d("WiFiP2pSyncActivity", "Updated device " + device.deviceName + " " + device.deviceAddress + ".");
+                    this.activity.updateOwnDeviceInformation(device);
+                    this.activity.searchForDevices();
+
+                }
+
+                @Override
+                public void onConnectionLost() {
+                    Toast.makeText(this.activity, CONNECTION_LOST_MESSAGE , Toast.LENGTH_LONG).show();
+                    if (this.activity.progressDialog != null && this.activity.progressDialog.isShowing()){
+                        this.activity.progressDialog.dismiss();
+                    }
+                }
+            }.init(this);
+        }
+
+        return _p2pEventListener;
+    }
+
+    /**
+     * Returns a instance of the wifi event handler. If no private instance was initiated it creates a new one.
+     * @return WiFiP2pEventHandler
+     */
+    private WiFiP2pEventHandler wifiEventHandler(){
+        if (this._wifiEventHandler == null){
+            this._wifiEventHandler = new WiFiP2pEventHandler(this, this.eventListener());
+        }
+        return this._wifiEventHandler;
+    }
+
+
+    /**
+     * Returns a sync completion listener. If no listener was initiated it creates a new on.
+     * @return BackgroundTaskCompletionListener
+     */
+    private BackgroundTask.BackgroundTaskCompletionListener syncCompletionListener(){
+        if (_syncCompletionListener == null){
+            _syncCompletionListener = new BackgroundTask.BackgroundTaskCompletionListener() {
+                WiFiP2pSyncActivity activity = null;
+                public BackgroundTask.BackgroundTaskCompletionListener init(WiFiP2pSyncActivity act){
+                    this.activity = act;
+                    return this;
+                }
+                @Override
+                public void didSucceed() {
+                    Toast.makeText(this.activity, SYNCHRONIZATION_COMPLETE_MESSAGE , Toast.LENGTH_SHORT).show();
+                    this.activity.wifiEventHandler().disconnect();
+                    this.activity.hostTask = null;
+                    this.activity.clientTask = null;
+                }
+
+                @Override
+                public void didFail() {
+                    Toast.makeText(this.activity, SYNCHRONIZATION_FAILED_MESSAGE, Toast.LENGTH_LONG).show();
+                    this.activity.wifiEventHandler().disconnect();
+                    this.activity.hostTask = null;
+                    this.activity.clientTask = null;
+                }
+            }.init(this);
+        }
+        return _syncCompletionListener;
+    }
+
+
+    /**
+     * Updates the device list on the ui thread.
+     * @param peers
+     */
+    private void updateDeviceListView(List<WifiP2pDevice> peers)
+    {
+        mTxtP2PSearchProgress.setVisibility(View.GONE);
+
+        this.discoveredDevices = new ArrayList<WifiP2pDevice>();
+        this.discoveredDevices.addAll(peers);
+        WiFiPeerListAdapter listAdapter = (WiFiPeerListAdapter) this.mLstP2PDevices.getAdapter();
+        listAdapter.addItems(peers);
+
+        // Run the update process on the gui thread, otherwise the list wont be updated.
+        this.runOnUiThread(new Runnable() {
+            private ListView listView;
+
+            @Override
+            public void run() {
+                WiFiPeerListAdapter adapter = (WiFiPeerListAdapter) this.listView.getAdapter();
+                this.listView.setAdapter(null);
+                adapter.notifyDataSetChanged();
+                this.listView.setAdapter(adapter);
+            }
+
+            public Runnable init(ListView listview) {
+                this.listView = listview;
+                return this;
+            }
+        }.init(this.mLstP2PDevices));
+        Log.d("WiFiP2pSyncActivity", " Discovered "+peers.size()+" devices.");
+
+        if (peers.size() == 0){
+            this.searchForDevices();
+        }
+    }
+
+    /**
+     * Starts the Host task. Informs the user by a little toast.
+     */
+    private void startHost()
+    {
+        if (this.hostTask == null){
+            Log.d("WiFiP2pSyncActivity", "Starting HOST Task" + ".");
+            //Toast.makeText(this, PERFORMING_TASK_AS_HOST , Toast.LENGTH_SHORT).show();
+            this.hostTask = new SyncHostTask(this.ownDevice, this.syncCompletionListener(), getApplicationContext());
+            this.executingTask = this.hostTask;
+            this.hostTask.execute();
+        } else {
+            Log.d("WiFiP2pSyncActivity", "Preventing third device for any syncing" + ".");
+        }
+
+    }
+
+    /**
+     * Starts the wifi direct client task. Informs the user by a little toast.
+     * @param info the WifiP2pInfo contains the groupOwnerAddress which is needed for the client task.
+     */
+    private void startClient(WifiP2pInfo info)
+    {
+        if (this.clientTask == null){
+            Log.d("WiFiP2pSyncActivity", "Starting CLIENT Task" + ".");
+            //Toast.makeText(this, PERFORMING_TASK_AS_CLIENT, Toast.LENGTH_SHORT).show();
+            this.clientTask = new SyncClientTask( info.groupOwnerAddress.getHostAddress(),this.ownDevice, this.syncCompletionListener(), getApplicationContext() );
+            this.executingTask = this.clientTask;
+            this.clientTask.execute();
+        } else {
+            Log.d("WiFiP2pSyncActivity", "Preventing third device for syncing" + ".");
+        }
+
+    }
+
+    /**
+     * Try to connect to the given device and shows a simple progress dialog.
+     * @param device
+     */
+    private void connectTo(WifiP2pDevice device){
+        String connectionTitle = PROGRESS_TITLE_CONNECTING;
+        if (device != null){
+            if (progressDialog == null){
+                this.progressDialog = ProgressDialog.show(this, "", connectionTitle);
+            } else {
+                progressDialog.setTitle(connectionTitle);
+            }
+            mOtherDevice = device;
+            this.wifiEventHandler().connect(device);
+        }
+    }
+
+    /**
+     * Returns a localized device status string.
+     * @param deviceStatus the status to convert.
+     * @return status string
+     */
+    private static String getDeviceStatus(int deviceStatus) {
+        switch (deviceStatus) {
+            case WifiP2pDevice.AVAILABLE:
+                return DEVICE_STATUS_AVAILABLE;
+            case WifiP2pDevice.INVITED:
+                return DEVICE_STATUS_INVITED;
+            case WifiP2pDevice.CONNECTED:
+                return DEVICE_STATUS_CONNECTED;
+            case WifiP2pDevice.FAILED:
+                return DEVICE_STATUS_FAILED;
+            case WifiP2pDevice.UNAVAILABLE:
+                return DEVICE_STATUS_UNAVAILABLE;
+            default:
+                return DEVICE_STATUS_UNKNOWN;
+        }
+    }
+
+    /**
+     * Updates / displays own device information.
+     * @param device
+     */
+    private void updateOwnDeviceInformation(WifiP2pDevice device)
+    {
+        mTxtP2PDeviceName.setText(device.deviceName);
+        mTxtP2PDeviceStatus.setText(getDeviceStatus(device.status));
+        ownDevice = device;
+    }
+
+    /**
+     * Method to search for new devices.
+     */
+    private void searchForDevices(){
+        mTxtP2PSearchProgress.setVisibility(View.VISIBLE);
+        this.wifiEventHandler().discoverDevices();
+    }
+
+    /********************** UI ************************/
+
+    /**
+     * Informs the user about a changed wifi state.
+     * enabled = true - mTxtP2PNotAvailable is gone
+     * enabled = false - mTxtP2PNotAvailable stays and a alert box is displayed for a quick navigation to the wifi settings.
+     * @param enabled
+     */
+    public void setWifiDirectAvailable(boolean enabled){
+        if (enabled){
+            mTxtP2PNotAvailable.setVisibility(View.GONE);
+        } else {
+            mTxtP2PNotAvailable.setVisibility(View.VISIBLE);
+            ((WiFiPeerListAdapter) mLstP2PDevices.getAdapter()).notifyDataSetChanged();
+            ownDevice = null;
+            this.updateDeviceListView(new ArrayList<WifiP2pDevice>());
+            this.showWifiDisabledDialog();
+            //Toast.makeText(this, "WiFi Direct P2P is disabled.", Toast.LENGTH_LONG).show();
+        }
+    }
+
+    /**
+     * Displays a AlertDialog that informs the User about the disabled Wifi state and can navigate the user directly to the wifi settings.
+     */
+    private void showWifiDisabledDialog(){
+        AlertDialog.Builder builder = new AlertDialog.Builder(this);
+        builder.setMessage(WIFI_STATUS_DISABLED_MESSAGE)
+                .setCancelable(true)
+                .setPositiveButton(WIFI_STATUS_ENABLE_BUTTON, new DialogInterface.OnClickListener() {
+                    public void onClick(DialogInterface dialog, int id) {
+                        startActivity(new Intent(Settings.ACTION_WIRELESS_SETTINGS));
+                    }
+                })
+                .setNegativeButton(CANCEL_BUTTON_TITLE, new DialogInterface.OnClickListener() {
+                    public void onClick(DialogInterface dialog, int id) {
+                        finish();
+                    }
+                });
+
+        AlertDialog info = builder.create();
+        info.show();
+    }
+
+    /**
+     * Extracts all subview initially from the view hierarchy.
+     */
+    private void extractFromView(){
+        this.mTxtP2PDeviceName = (TextView) findViewById(R.id.txt_p2p_device_name);
+        this.mTxtP2PDeviceStatus = (TextView) findViewById(R.id.txt_p2p_device_status);
+        this.mTxtP2PChangeDeviceName = (TextView) findViewById(R.id.txtP2PChangeDeviceName);
+
+        this.mViewAnimator = (ViewAnimator) findViewById(R.id.viewAnimator);
+        this.mDevicesContainer = (RelativeLayout) findViewById(R.id.devicesContainer);
+        this.mWelcomeContainer = (RelativeLayout) findViewById(R.id.welcomeContainer);
+        this.mTxtP2PSearchProgress = (TextView) findViewById(R.id.txtP2PSearchProgress);
+        this.mLstP2PDevices = (ListView) findViewById(R.id.lstP2PDevices);
+        this.mTxtP2PNotAvailable = (TextView) findViewById(R.id.txtP2PNotAvailable);
+    }
+
+    /**
+     * Registers all the gui listeners.
+     */
+    public void registerListeners(){
+        if (this.mLstP2PDevices.getOnItemClickListener() != this)
+            this.mLstP2PDevices.setOnItemClickListener(this);
+
+        if (this.mLstP2PDevices.getAdapter() == null){
+            this.discoveredDevices = new ArrayList();
+            WiFiPeerListAdapter listAdapter = new WiFiPeerListAdapter(this, R.layout.row_devices, this.discoveredDevices);
+            this.mLstP2PDevices.setAdapter(listAdapter);
+        }
+    }
+
+
+    @Override
+    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+        final WifiP2pDevice device = (WifiP2pDevice) this.mLstP2PDevices.getAdapter().getItem(position);
+        this.connectTo(device);
+    }
+
+
+    /**
+     * Array adapter for ListFragment that maintains WifiP2pDevice list.
+     */
+    private class WiFiPeerListAdapter extends ArrayAdapter<WifiP2pDevice> {
+        private List<WifiP2pDevice> items;
+        /**
+         * @param context
+         * @param textViewResourceId
+         * @param objects
+         */
+        public WiFiPeerListAdapter(Context context, int textViewResourceId,
+                                   List<WifiP2pDevice> objects) {
+            super(context, textViewResourceId, objects);
+            items = objects;
+        }
+
+        @Override
+        public int getCount() {
+            return items.size();
+        }
+
+
+        public void addItems(List<WifiP2pDevice> devicesToAdd){
+            items.clear();
+            items.addAll(devicesToAdd);
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            View v = convertView;
+            if (v == null) {
+                LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+                v = vi.inflate(R.layout.row_devices, null);
+            }
+            WifiP2pDevice device = items.get(position);
+            if (device != null) {
+                TextView top = (TextView) v.findViewById(R.id.device_name);
+                TextView bottom = (TextView) v.findViewById(R.id.device_details);
+                if (top != null) {
+                    top.setText(device.deviceName);
+                }
+                if (bottom != null) {
+                    bottom.setText(getDeviceStatus(device.status));
+                }
+            }
+            return v;
+        }
+    }
+}

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

@@ -38,6 +38,7 @@ 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.sync.android.SyncUtils;
 import de.tudarmstadt.informatik.hostage.system.Device;
 import de.tudarmstadt.informatik.hostage.ui.model.LogFilter;
 import de.tudarmstadt.informatik.hostage.ui.adapter.DrawerListAdapter;
@@ -187,6 +188,9 @@ public class MainActivity extends Activity {
 	public void onStart() {
 		super.onStart();
 
+        // Register syncing with android
+        SyncUtils.CreateSyncAccount(this);
+
 		if (isServiceRunning()) {
 			this.bindService();
 		}

+ 48 - 1
src/de/tudarmstadt/informatik/hostage/ui/fragment/PreferenceHostageFragment.java

@@ -1,23 +1,31 @@
 package de.tudarmstadt.informatik.hostage.ui.fragment;
 
 import android.content.SharedPreferences;
+import android.os.AsyncTask;
 import android.os.Bundle;
 import android.preference.EditTextPreference;
+import android.preference.MultiSelectListPreference;
 import android.preference.Preference;
 import android.preference.PreferenceFragment;
 
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 
 import de.tudarmstadt.informatik.hostage.R;
+import de.tudarmstadt.informatik.hostage.sync.android.SyncUtils;
 
 /**
  * Manages and creates the application preferences view
  *
  * @author Alexander Brakowski
  * @created 02.03.14 21:03
- */
+*/
 public class PreferenceHostageFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener {
 
+    public static CharSequence[] entries = null;
+    public static CharSequence[] entriesValues = null;
+
 	/**
 	 * Maps an text preference to an suffix string
 	 */
@@ -34,6 +42,7 @@ public class PreferenceHostageFragment extends PreferenceFragment implements Sha
 		String[] textPreferences = new String[]{
 				"pref_external_location",
 				"pref_upload_server",
+                "pref_download_server",
 				"pref_max_connections",
 				"pref_timeout",
 				"pref_sleeptime",
@@ -52,8 +61,42 @@ public class PreferenceHostageFragment extends PreferenceFragment implements Sha
 		for(String k: textPreferences){
 			updatePreferenceSummary(k);
 		}
+
+        if(entries == null || entriesValues == null) {
+            refreshCountryList();
+        }
 	}
 
+    private void refreshCountryList(){
+        final SharedPreferences sharedPreferences = this.getPreferenceManager().getSharedPreferences();
+
+        Preference p = getPreferenceManager().findPreference("pref_sync_countries");
+        final MultiSelectListPreference mp = (MultiSelectListPreference) p;
+
+        AsyncTask<String, Void, List<String[]>> task = new AsyncTask<String, Void, List<String[]>>(){
+            @Override
+            protected List<String[]> doInBackground(String... params) {
+                return SyncUtils.getCountriesFromServer(sharedPreferences.getString("pref_download_server", "http://192.168.1.118:8888"));
+            }
+
+            protected void onPostExecute(List<String[]> lst) {
+                if(lst != null) {
+                    entries = new CharSequence[lst.size()];
+                    entriesValues = new CharSequence[lst.size()];
+
+                    for (int i = 0; i < lst.size(); i++) {
+                        entries[i] = lst.get(i)[1];
+                        entriesValues[i] = lst.get(i)[0];
+                    }
+
+                    mp.setEntries(entries);
+                    mp.setEntryValues(entriesValues);
+                }
+            }
+        };
+
+        task.execute();
+    }
 	/**
 	 * Updates the summary text of the given preference
 	 *
@@ -113,6 +156,10 @@ public class PreferenceHostageFragment extends PreferenceFragment implements Sha
 	 */
 	@Override
 	public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
+        if(key.equals("pref_download_server")){
+            refreshCountryList();
+        }
+
 		updatePreferenceSummary(key);
 	}
 }

+ 3 - 5
src/de/tudarmstadt/informatik/hostage/ui/fragment/RecordOverviewFragment.java

@@ -44,14 +44,12 @@ 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.logging.SyncData;
-import de.tudarmstadt.informatik.hostage.logging.SyncDevice;
 import de.tudarmstadt.informatik.hostage.logging.SyncInfo;
 import de.tudarmstadt.informatik.hostage.persistence.HostageDBOpenHelper;
-import de.tudarmstadt.informatik.hostage.sync.Synchronizer;
 import de.tudarmstadt.informatik.hostage.sync.bluetooth.BluetoothSyncActivity;
 import de.tudarmstadt.informatik.hostage.sync.nfc.NFCSyncActivity;
-import de.tudarmstadt.informatik.hostage.sync.p2p.P2PSyncActivity;
 import de.tudarmstadt.informatik.hostage.sync.tracing.TracingSyncActivity;
+import de.tudarmstadt.informatik.hostage.sync.wifi_direct.ui.WiFiP2pSyncActivity;
 import de.tudarmstadt.informatik.hostage.ui.activity.MainActivity;
 import de.tudarmstadt.informatik.hostage.ui.adapter.RecordListAdapter;
 import de.tudarmstadt.informatik.hostage.ui.dialog.ChecklistDialog;
@@ -152,7 +150,7 @@ public class RecordOverviewFragment extends UpNavigatibleFragment implements Che
 	    pref = PreferenceManager.getDefaultSharedPreferences(getActivity());
 
 	    // Get the message from the intent
-        // this.addRecordToDB(4,4,4);
+        //this.addRecordToDB(4,4,4);
         /*
          Synchronizer s = new Synchronizer(this.dbh);
          si = s.getSyncInfo();
@@ -395,7 +393,7 @@ public class RecordOverviewFragment extends UpNavigatibleFragment implements Che
 								getActivity().startActivity(new Intent(getActivity(), TracingSyncActivity.class));
 								break;
                             case 3:
-                                getActivity().startActivity(new Intent(getActivity(), P2PSyncActivity.class));
+                                getActivity().startActivity(new Intent(getActivity(), WiFiP2pSyncActivity.class));
                                 break;
 						}
 					}