Răsfoiți Sursa

Refactoring: Added comments to every class, as well as a copyright
notice. Also, some classes were moved to packages where they make sense

Lennart Rosam 13 ani în urmă
părinte
comite
dc8c32fb3f
36 a modificat fișierele cu 3651 adăugiri și 3161 ștergeri
  1. 75 76
      AndroidManifest.xml
  2. 38 38
      res/layout/action_bar.xml
  3. 0 37
      src/eu/alefzero/owncloud/ActionItem.java
  4. 80 75
      src/eu/alefzero/owncloud/DisplayUtils.java
  5. 77 76
      src/eu/alefzero/owncloud/FileDownloader.java
  6. 55 33
      src/eu/alefzero/owncloud/OwnCloudSession.java
  7. 468 445
      src/eu/alefzero/owncloud/Uploader.java
  8. 235 235
      src/eu/alefzero/owncloud/authenticator/AccountAuthenticator.java
  9. 243 243
      src/eu/alefzero/owncloud/authenticator/AuthUtils.java
  10. 215 210
      src/eu/alefzero/owncloud/cp.java
  11. 103 79
      src/eu/alefzero/owncloud/db/DbHandler.java
  12. 64 59
      src/eu/alefzero/owncloud/db/ProviderMeta.java
  13. 187 170
      src/eu/alefzero/owncloud/syncadapter/AbstractOwnCloudSyncAdapter.java
  14. 142 140
      src/eu/alefzero/owncloud/syncadapter/FileSyncAdapter.java
  15. 53 31
      src/eu/alefzero/owncloud/syncadapter/FileSyncService.java
  16. 59 0
      src/eu/alefzero/owncloud/ui/ActionItem.java
  17. 148 126
      src/eu/alefzero/owncloud/ui/CustomPopup.java
  18. 23 1
      src/eu/alefzero/owncloud/ui/QuickAction.java
  19. 191 186
      src/eu/alefzero/owncloud/ui/activity/AuthenticatorActivity.java
  20. 24 1
      src/eu/alefzero/owncloud/ui/activity/FileDetailActivity.java
  21. 8 2
      src/eu/alefzero/owncloud/ui/activity/FileDisplayActivity.java
  22. 3 3
      src/eu/alefzero/owncloud/ui/activity/LandingActivity.java
  23. 168 146
      src/eu/alefzero/owncloud/ui/activity/Preferences.java
  24. 143 143
      src/eu/alefzero/owncloud/ui/activity/PreferencesNewSession.java
  25. 131 108
      src/eu/alefzero/owncloud/ui/adapter/FileListListAdapter.java
  26. 104 87
      src/eu/alefzero/owncloud/ui/adapter/LandingScreenAdapter.java
  27. 66 45
      src/eu/alefzero/owncloud/ui/fragment/ActionBar.java
  28. 22 0
      src/eu/alefzero/owncloud/ui/fragment/FileDetail.java
  29. 23 1
      src/eu/alefzero/owncloud/ui/fragment/FileList.java
  30. 24 0
      src/eu/alefzero/owncloud/ui/fragment/LandingPageFragment.java
  31. 117 92
      src/eu/alefzero/owncloud/ui/fragment/PathLayout.java
  32. 36 19
      src/eu/alefzero/webdav/HttpMkCol.java
  33. 49 32
      src/eu/alefzero/webdav/HttpPropFind.java
  34. 43 26
      src/eu/alefzero/webdav/HttpPropPatch.java
  35. 38 21
      src/eu/alefzero/webdav/TreeNodeContainer.java
  36. 196 175
      src/eu/alefzero/webdav/WebdavClient.java

+ 75 - 76
AndroidManifest.xml

@@ -1,77 +1,76 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-      package="eu.alefzero.owncloud"
-      android:versionCode="1"
-      android:versionName="1.0">
-<uses-permission
-        android:name="android.permission.GET_ACCOUNTS" />
-    <uses-permission
-        android:name="android.permission.USE_CREDENTIALS" />
-    <uses-permission
-        android:name="android.permission.MANAGE_ACCOUNTS" />
-    <uses-permission
-        android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
-    <uses-permission
-        android:name="android.permission.INTERNET" />
-    <uses-permission
-        android:name="android.permission.WRITE_SETTINGS" />
-    <uses-permission
-        android:name="android.permission.READ_SYNC_STATS" />
-    <uses-permission
-        android:name="android.permission.READ_SYNC_SETTINGS" />
-    <uses-permission
-        android:name="android.permission.WRITE_SYNC_SETTINGS" />
-    <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="10" />
-    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
-
-    <application android:icon="@drawable/icon" android:label="@string/app_name">
-        <activity android:name=".ui.FileDisplayActivity"></activity>
-        <activity android:name=".Uploader">
-            <intent-filter>
-                <action android:name="android.intent.action.SEND"></action>
-                <category android:name="android.intent.category.DEFAULT"></category>
-                <data android:mimeType="*/*"></data>
-            </intent-filter>
-            <intent-filter>
-                <action android:name="android.intent.action.SEND_MULTIPLE"></action>
-                <category android:name="android.intent.category.DEFAULT"></category>
-                <data android:mimeType="*/*"></data>
-            </intent-filter>
-        </activity>
-        <activity android:name=".ui.Preferences"></activity>
-        <activity android:name=".ui.PreferencesNewSession">
-        </activity>
-                <service
-            android:exported="true" android:name=".authenticator.AccountAuthenticatorService">
-            <intent-filter>
-                <action
-                    android:name="android.accounts.AccountAuthenticator" />
-            </intent-filter>
-            <meta-data
-                android:name="android.accounts.AccountAuthenticator"
-                android:resource="@xml/authenticator" />
-        </service>
-         <service
-            android:exported="true" android:name=".syncadapter.FileSyncService">
-            <intent-filter>
-                <action android:name="android.content.SyncAdapter"/>
-            </intent-filter>
-            <meta-data
-                android:name="android.content.SyncAdapter"
-                android:resource="@xml/syncadapter_files"/>
-        </service>
-         <provider android:name=".cp" android:enabled="true" android:syncable="true" android:exported="false" android:authorities="org.owncloud" android:label="@string/sync_string_files"></provider>
-         <activity android:name=".ui.AuthenticatorActivity"></activity>
-         <service android:name=".FileDownloader">
-         </service>
-         <activity android:name=".ui.FileDetailActivity"></activity>
-         <activity android:name=".ui.LandingActivity"
-             android:theme="@android:style/Theme.NoTitleBar"
-             android:label="@string/app_name">
-             <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-         </activity>
-    </application>
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+      package="eu.alefzero.owncloud"
+      android:versionCode="1"
+      android:versionName="1.0">
+<uses-permission
+        android:name="android.permission.GET_ACCOUNTS" />
+    <uses-permission
+        android:name="android.permission.USE_CREDENTIALS" />
+    <uses-permission
+        android:name="android.permission.MANAGE_ACCOUNTS" />
+    <uses-permission
+        android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
+    <uses-permission
+        android:name="android.permission.INTERNET" />
+    <uses-permission
+        android:name="android.permission.WRITE_SETTINGS" />
+    <uses-permission
+        android:name="android.permission.READ_SYNC_STATS" />
+    <uses-permission
+        android:name="android.permission.READ_SYNC_SETTINGS" />
+    <uses-permission
+        android:name="android.permission.WRITE_SYNC_SETTINGS" />
+    <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="10" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
+
+    <application android:icon="@drawable/icon" android:label="@string/app_name">
+        <activity android:name=".ui.activity.FileDisplayActivity"></activity>
+        <activity android:name=".Uploader">
+            <intent-filter>
+                <action android:name="android.intent.action.SEND"></action>
+                <category android:name="android.intent.category.DEFAULT"></category>
+                <data android:mimeType="*/*"></data>
+            </intent-filter>
+            <intent-filter>
+                <action android:name="android.intent.action.SEND_MULTIPLE"></action>
+                <category android:name="android.intent.category.DEFAULT"></category>
+                <data android:mimeType="*/*"></data>
+            </intent-filter>
+        </activity>
+        <activity android:name=".ui.activity.Preferences"></activity>
+        <activity android:name=".ui.activity.PreferencesNewSessionewSession"></activity>
+                <service
+            android:exported="true" android:name=".authenticator.AccountAuthenticatorService">
+            <intent-filter>
+                <action
+                    android:name="android.accounts.AccountAuthenticator" />
+            </intent-filter>
+            <meta-data
+                android:name="android.accounts.AccountAuthenticator"
+                android:resource="@xml/authenticator" />
+        </service>
+         <service
+            android:exported="true" android:name=".syncadapter.FileSyncService">
+            <intent-filter>
+                <action android:name="android.content.SyncAdapter"/>
+            </intent-filter>
+            <meta-data
+                android:name="android.content.SyncAdapter"
+                android:resource="@xml/syncadapter_files"/>
+        </service>
+         <provider android:name=".cp" android:enabled="true" android:syncable="true" android:exported="false" android:authorities="org.owncloud" android:label="@string/sync_string_files"></provider>
+         <activity android:name=".ui.activity.AuthenticatorActivity"></activity>
+         <service android:name=".FileDownloader">
+         </service>
+         <activity android:name=".ui.activity.FileDetailActivity"></activity>
+         <activity android:name=".ui.activity.LandingActivity"
+             android:theme="@android:style/Theme.NoTitleBar"
+             android:label="@string/app_name">
+             <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+         </activity>
+    </application>
 </manifest>

+ 38 - 38
res/layout/action_bar.xml

@@ -1,39 +1,39 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="fill_parent"
-    android:layout_height="wrap_content"
-    android:background="#F7F7F7"
-    android:orientation="vertical" >
-
-    <LinearLayout
-        android:id="@+id/linearLayout1"
-        android:layout_width="fill_parent"
-        android:layout_height="fill_parent"
-        android:orientation="vertical" >
-
-        <LinearLayout
-            android:id="@+id/linearLayout7"
-            android:layout_width="fill_parent"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center_vertical"
-            android:background="@drawable/main_header_bg"
-            android:gravity="top"
-            android:orientation="horizontal" >
-
-            <ImageView
-                android:id="@+id/main_header_small"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_gravity="center_vertical|left"
-                android:src="@drawable/icon" >
-            </ImageView>
-
-            <eu.alefzero.owncloud.PathLayout
-                android:id="@+id/pathLayout1"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_gravity="center_vertical" >
-            </eu.alefzero.owncloud.PathLayout>
-        </LinearLayout>
-    </LinearLayout>
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content"
+    android:background="#F7F7F7"
+    android:orientation="vertical" >
+
+    <LinearLayout
+        android:id="@+id/linearLayout1"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:orientation="vertical" >
+
+        <LinearLayout
+            android:id="@+id/linearLayout7"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical"
+            android:background="@drawable/main_header_bg"
+            android:gravity="top"
+            android:orientation="horizontal" >
+
+            <ImageView
+                android:id="@+id/main_header_small"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_vertical|left"
+                android:src="@drawable/icon" >
+            </ImageView>
+
+            <eu.alefzero.owncloud.ui.fragment.PathLayout
+                android:id="@+id/pathLayout1"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_vertical" >
+            </eu.alefzero.owncloud.ui.fragment.PathLayout>
+        </LinearLayout>
+    </LinearLayout>
 </LinearLayout>

+ 0 - 37
src/eu/alefzero/owncloud/ActionItem.java

@@ -1,37 +0,0 @@
-package eu.alefzero.owncloud;
-
-import android.graphics.drawable.Drawable;
-import android.view.View.OnClickListener;
-
-public class ActionItem {
-  private Drawable mIcon;
-  private String mTitle;
-  private OnClickListener mClickListener;
-  
-  public ActionItem() { }
-  
-  public void setTitle(String title) {
-    mTitle = title;
-  }
-  
-  public String getTitle() {
-    return mTitle;
-  }
-  
-  public void setIcon(Drawable icon) {
-    mIcon = icon;
-  }
-  
-  public Drawable getIcon() {
-    return mIcon;
-  }
-  
-  public void setOnClickListener(OnClickListener listener) {
-    mClickListener = listener;
-  }
-  
-  public OnClickListener getOnClickListerner() {
-    return mClickListener;
-  }
-  
-}

+ 80 - 75
src/eu/alefzero/owncloud/DisplayUtils.java

@@ -1,75 +1,80 @@
-/* ownCloud Android client application
- *   Copyright (C) 2011  Bartek Przybylski
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation, either version 3 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-package eu.alefzero.owncloud;
-
-import java.util.HashMap;
-
-import android.util.Log;
-
-public class DisplayUtils {
-  public static String bitsToHumanReadable(long bitsLen) {
-    double result = bitsLen;
-    int attachedsuff = 0;
-    while (result > 1024 && attachedsuff < suffixes.length) {
-      result /= 1024.;
-      attachedsuff++;
-    }
-    result = ((int)(result * 100))/100.;
-    return result+suffixes[attachedsuff];
-  }
-  
-  public static String HtmlDecode(String s) {
-    String ret = "";
-    for (int i = 0; i < s.length(); ++i) {
-      if (s.charAt(i) == '%') {
-        ret += (char)Integer.parseInt(s.substring(i+1, i+3), 16);
-        i+=2;
-      } else {
-        ret += s.charAt(i);
-      }
-    }
-    return ret;
-  }
-
-  public static String convertMIMEtoPrettyPrint(String mimetype) {
-    if (mimeType2HUmanReadable.containsKey(mimetype)) {
-      return mimeType2HUmanReadable.get(mimetype);
-    }
-    return mimetype.split("/")[1].toUpperCase() + " file";
-  }
-  
-  private static final String[] suffixes = {"B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"};
-  
-  private static HashMap<String, String> mimeType2HUmanReadable;
-  static {
-    mimeType2HUmanReadable = new HashMap<String, String>();
-    // images
-    mimeType2HUmanReadable.put("image/jpeg", "JPEG image");
-    mimeType2HUmanReadable.put("image/jpg", "JPEG image");
-    mimeType2HUmanReadable.put("image/png", "PNG image");
-    mimeType2HUmanReadable.put("image/bmp", "Bitmap image");
-    mimeType2HUmanReadable.put("image/gif", "GIF image");
-    mimeType2HUmanReadable.put("image/svg+xml", "JPEG image");
-    mimeType2HUmanReadable.put("image/tiff", "TIFF image");
-    // music
-    mimeType2HUmanReadable.put("audio/mpeg", "MP3 music file");
-    mimeType2HUmanReadable.put("application/ogg", "OGG music file");
-    
-  }
-}
+/* ownCloud Android client application
+ *   Copyright (C) 2011  Bartek Przybylski
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package eu.alefzero.owncloud;
+
+import java.util.HashMap;
+
+import android.util.Log;
+
+/**
+ * A helper class for some string operations.
+ * @author Bartek Przybylski
+ *
+ */
+public class DisplayUtils {
+  public static String bitsToHumanReadable(long bitsLen) {
+    double result = bitsLen;
+    int attachedsuff = 0;
+    while (result > 1024 && attachedsuff < suffixes.length) {
+      result /= 1024.;
+      attachedsuff++;
+    }
+    result = ((int)(result * 100))/100.;
+    return result+suffixes[attachedsuff];
+  }
+  
+  public static String HtmlDecode(String s) {
+    String ret = "";
+    for (int i = 0; i < s.length(); ++i) {
+      if (s.charAt(i) == '%') {
+        ret += (char)Integer.parseInt(s.substring(i+1, i+3), 16);
+        i+=2;
+      } else {
+        ret += s.charAt(i);
+      }
+    }
+    return ret;
+  }
+
+  public static String convertMIMEtoPrettyPrint(String mimetype) {
+    if (mimeType2HUmanReadable.containsKey(mimetype)) {
+      return mimeType2HUmanReadable.get(mimetype);
+    }
+    return mimetype.split("/")[1].toUpperCase() + " file";
+  }
+  
+  private static final String[] suffixes = {"B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"};
+  
+  private static HashMap<String, String> mimeType2HUmanReadable;
+  static {
+    mimeType2HUmanReadable = new HashMap<String, String>();
+    // images
+    mimeType2HUmanReadable.put("image/jpeg", "JPEG image");
+    mimeType2HUmanReadable.put("image/jpg", "JPEG image");
+    mimeType2HUmanReadable.put("image/png", "PNG image");
+    mimeType2HUmanReadable.put("image/bmp", "Bitmap image");
+    mimeType2HUmanReadable.put("image/gif", "GIF image");
+    mimeType2HUmanReadable.put("image/svg+xml", "JPEG image");
+    mimeType2HUmanReadable.put("image/tiff", "TIFF image");
+    // music
+    mimeType2HUmanReadable.put("audio/mpeg", "MP3 music file");
+    mimeType2HUmanReadable.put("application/ogg", "OGG music file");
+    
+  }
+}

+ 77 - 76
src/eu/alefzero/owncloud/FileDownloader.java

@@ -1,76 +1,77 @@
-package eu.alefzero.owncloud;
-
-import java.io.File;
-
-import android.accounts.Account;
-import android.accounts.AccountManager;
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.app.Service;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Environment;
-import android.os.IBinder;
-import android.util.Log;
-import eu.alefzero.owncloud.authenticator.AccountAuthenticator;
-import eu.alefzero.owncloud.ui.FileDisplayActivity;
-
-public class FileDownloader extends Service {
-  static final String EXTRA_ACCOUNT = "ACCOUNT";
-  static final String EXTRA_FILE_PATH = "FILE_PATH";
-  static final String TAG = "OC_FileDownloader";
-  
-  NotificationManager nm;
-  
-  @Override
-  public IBinder onBind(Intent arg0) {
-    return null;
-  }
-  
-  @Override
-  public int onStartCommand(Intent intent, int flags, int startId) {
-    if (!intent.hasExtra(EXTRA_ACCOUNT) && !intent.hasExtra(EXTRA_FILE_PATH)) {
-      Log.e(TAG, "Not enough information provided in intent");
-      return START_NOT_STICKY;
-    }
-    
-    nm = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
-    
-    Account account = intent.getParcelableExtra(EXTRA_ACCOUNT);
-    String file_path = intent.getStringExtra(EXTRA_FILE_PATH);
-    AccountManager am = (AccountManager)getSystemService(ACCOUNT_SERVICE);
-    Uri oc_url = Uri.parse(am.getUserData(account, AccountAuthenticator.KEY_OC_URL));
-
-    WebdavClient wdc = new WebdavClient(oc_url);
-    
-    String username = account.name.split("@")[0];
-    String password = "";
-    try {
-      password = am.blockingGetAuthToken(account, AccountAuthenticator.AUTH_TOKEN_TYPE, true);
-    } catch (Exception e) {
-      // TODO Auto-generated catch block
-      e.printStackTrace();
-      return START_NOT_STICKY;
-    }
-    
-    wdc.setCredentials(username, password);
-    wdc.allowUnsignedCertificates();
-
-    Notification n = new Notification(R.drawable.icon, "Downloading file", System.currentTimeMillis());
-    PendingIntent pi = PendingIntent.getActivity(this, 1, new Intent(this, FileDisplayActivity.class), 0);
-    n.setLatestEventInfo(this, "A", "B", pi);
-    nm.notify(1, n);
-
-    File sdCard = Environment.getExternalStorageDirectory();
-    File dir = new File (sdCard.getAbsolutePath() + "/owncloud");
-    dir.mkdirs();
-    File file = new File(dir, file_path.replace('/', '.'));
-    
-    wdc.downloadFile(file_path, file);
-    
-    return START_NOT_STICKY;
-  }
-  
-  
-}
+package eu.alefzero.owncloud;
+
+import java.io.File;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.app.Service;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Environment;
+import android.os.IBinder;
+import android.util.Log;
+import eu.alefzero.owncloud.authenticator.AccountAuthenticator;
+import eu.alefzero.owncloud.ui.activity.FileDisplayActivity;
+import eu.alefzero.webdav.WebdavClient;
+
+public class FileDownloader extends Service {
+  static final String EXTRA_ACCOUNT = "ACCOUNT";
+  static final String EXTRA_FILE_PATH = "FILE_PATH";
+  static final String TAG = "OC_FileDownloader";
+  
+  NotificationManager nm;
+  
+  @Override
+  public IBinder onBind(Intent arg0) {
+    return null;
+  }
+  
+  @Override
+  public int onStartCommand(Intent intent, int flags, int startId) {
+    if (!intent.hasExtra(EXTRA_ACCOUNT) && !intent.hasExtra(EXTRA_FILE_PATH)) {
+      Log.e(TAG, "Not enough information provided in intent");
+      return START_NOT_STICKY;
+    }
+    
+    nm = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
+    
+    Account account = intent.getParcelableExtra(EXTRA_ACCOUNT);
+    String file_path = intent.getStringExtra(EXTRA_FILE_PATH);
+    AccountManager am = (AccountManager)getSystemService(ACCOUNT_SERVICE);
+    Uri oc_url = Uri.parse(am.getUserData(account, AccountAuthenticator.KEY_OC_URL));
+
+    WebdavClient wdc = new WebdavClient(oc_url);
+    
+    String username = account.name.split("@")[0];
+    String password = "";
+    try {
+      password = am.blockingGetAuthToken(account, AccountAuthenticator.AUTH_TOKEN_TYPE, true);
+    } catch (Exception e) {
+      // TODO Auto-generated catch block
+      e.printStackTrace();
+      return START_NOT_STICKY;
+    }
+    
+    wdc.setCredentials(username, password);
+    wdc.allowUnsignedCertificates();
+
+    Notification n = new Notification(R.drawable.icon, "Downloading file", System.currentTimeMillis());
+    PendingIntent pi = PendingIntent.getActivity(this, 1, new Intent(this, FileDisplayActivity.class), 0);
+    n.setLatestEventInfo(this, "A", "B", pi);
+    nm.notify(1, n);
+
+    File sdCard = Environment.getExternalStorageDirectory();
+    File dir = new File (sdCard.getAbsolutePath() + "/owncloud");
+    dir.mkdirs();
+    File file = new File(dir, file_path.replace('/', '.'));
+    
+    wdc.downloadFile(file_path, file);
+    
+    return START_NOT_STICKY;
+  }
+  
+  
+}

+ 55 - 33
src/eu/alefzero/owncloud/OwnCloudSession.java

@@ -1,33 +1,55 @@
-package eu.alefzero.owncloud;
-
-public class OwnCloudSession {
-  private String mSessionName;
-  private String mSessionUrl;
-  private int mEntryId;
-  
-  public OwnCloudSession(String name, String url, int entryId) {
-    mSessionName = name;
-    mSessionUrl = url;
-    mEntryId = entryId;
-  }
-  
-  public void setName(String name) {
-    mSessionName = name;
-  }
-  
-  public String getName() {
-    return mSessionName;
-  }
-  
-  public void setUrl(String url) {
-    mSessionUrl = url;
-  }
-  
-  public String getUrl() {
-    return mSessionUrl;
-  }
-  
-  public int getEntryId() {
-    return mEntryId;
-  }
-}
+/* ownCloud Android client application
+ *   Copyright (C) 2011  Bartek Przybylski
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package eu.alefzero.owncloud;
+
+/**
+ * Represents a session to an ownCloud instance
+ * @author Bartek Przybylski
+ *
+ */
+public class OwnCloudSession {
+  private String mSessionName;
+  private String mSessionUrl;
+  private int mEntryId;
+  
+  public OwnCloudSession(String name, String url, int entryId) {
+    mSessionName = name;
+    mSessionUrl = url;
+    mEntryId = entryId;
+  }
+  
+  public void setName(String name) {
+    mSessionName = name;
+  }
+  
+  public String getName() {
+    return mSessionName;
+  }
+  
+  public void setUrl(String url) {
+    mSessionUrl = url;
+  }
+  
+  public String getUrl() {
+    return mSessionUrl;
+  }
+  
+  public int getEntryId() {
+    return mEntryId;
+  }
+}

+ 468 - 445
src/eu/alefzero/owncloud/Uploader.java

@@ -1,445 +1,468 @@
-package eu.alefzero.owncloud;
-
-import java.io.File;
-import java.net.FileNameMap;
-import java.net.URI;
-import java.net.URLConnection;
-import java.util.ArrayList;
-import java.util.Stack;
-
-import android.accounts.Account;
-import android.accounts.AccountManager;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.app.ListActivity;
-import android.app.ProgressDialog;
-import android.app.AlertDialog.Builder;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.DialogInterface.OnCancelListener;
-import android.content.DialogInterface.OnClickListener;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Parcelable;
-import android.provider.MediaStore.Images.Media;
-import android.util.Log;
-import android.view.View;
-import android.view.Window;
-import android.view.ViewGroup.LayoutParams;
-import android.widget.AdapterView;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.LinearLayout;
-import android.widget.ListView;
-import android.widget.SimpleCursorAdapter;
-import android.widget.Toast;
-import android.widget.AdapterView.OnItemClickListener;
-import eu.alefzero.owncloud.authenticator.AccountAuthenticator;
-import eu.alefzero.owncloud.db.ProviderMeta;
-import eu.alefzero.owncloud.db.ProviderMeta.ProviderTableMeta;
-import eu.alefzero.webdav.WebdavUtils;
-
-public class Uploader extends ListActivity implements OnItemClickListener, android.view.View.OnClickListener {
-  private static final String TAG = "ownCloudUploader";
-
-  private Account mAccount;
-  private AccountManager mAccountManager;
-  private String mUsername, mPassword;
-  private Cursor mCursor;
-  private Stack<String> mParents;
-  private Thread mUploadThread;
-  private Handler mHandler;
-  private ArrayList<Parcelable> mStreamsToUpload;
-
-  private final static int DIALOG_NO_ACCOUNT = 0;
-  private final static int DIALOG_WAITING = 1;
-  private final static int DIALOG_NO_STREAM = 2;
-  private final static int DIALOG_MULTIPLE_ACCOUNT = 3;
-  private final static int DIALOG_GET_DIRNAME = 4;
-
-  private final static int REQUEST_CODE_SETUP_ACCOUNT = 0;
-
-  @Override
-  protected void onCreate(Bundle savedInstanceState) {
-    super.onCreate(savedInstanceState);
-    getWindow().requestFeature(Window.FEATURE_NO_TITLE);
-    mParents = new Stack<String>();
-    mHandler = new Handler();
-    if (getIntent().hasExtra(Intent.EXTRA_STREAM)) {
-      prepareStreamsToUpload();
-      mAccountManager = (AccountManager)getSystemService(Context.ACCOUNT_SERVICE);
-      Account[] accounts = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE);
-      if (accounts.length == 0) {
-        Log.i(TAG, "No ownCloud account is available");
-        showDialog(DIALOG_NO_ACCOUNT);
-      } else if (accounts.length > 1) {
-        Log.i(TAG, "More then one ownCloud is available");
-        showDialog(DIALOG_MULTIPLE_ACCOUNT);
-      } else {
-        mAccount = accounts[0];
-        setContentView(R.layout.uploader_layout);
-        populateDirectoryList();
-      }
-    } else {
-      showDialog(DIALOG_NO_STREAM);
-    }
-  }
-
-  @Override
-  protected Dialog onCreateDialog(final int id) {
-    final AlertDialog.Builder builder = new Builder(this);
-    switch (id) {
-      case DIALOG_WAITING:
-        ProgressDialog pDialog = new ProgressDialog(this);
-        pDialog.setIndeterminate(false);
-        pDialog.setCancelable(false);
-        pDialog.setMessage(getResources().getString(R.string.uploader_info_uploading));
-        return pDialog;
-      case DIALOG_NO_ACCOUNT:
-        builder.setIcon(android.R.drawable.ic_dialog_alert);
-        builder.setTitle(R.string.uploader_wrn_no_account_title);
-        builder.setMessage(R.string.uploader_wrn_no_account_text);
-        builder.setCancelable(false);
-        builder.setPositiveButton(R.string.uploader_wrn_no_account_setup_btn_text, new OnClickListener() {
-          public void onClick(DialogInterface dialog, int which) {
-            if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.ECLAIR_MR1) {
-              // using string value since in API7 this constatn is not defined
-              // in API7 < this constatant is defined in Settings.ADD_ACCOUNT_SETTINGS
-              // and Settings.EXTRA_AUTHORITIES
-              Intent intent = new Intent("android.settings.ADD_ACCOUNT_SETTINGS");
-              intent.putExtra("authorities", new String[] {AccountAuthenticator.AUTH_TOKEN_TYPE});
-              startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT);
-            } else {
-              // since in API7 there is no direct call for account setup, so we need to
-              // show our own AccountSetupAcricity, get desired results and setup
-              // everything for ourself
-              Intent intent = new Intent(getBaseContext(), AccountAuthenticator.class);
-              startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT);
-            }
-          }
-        });
-        builder.setNegativeButton(R.string.uploader_wrn_no_account_quit_btn_text, new OnClickListener() {
-          public void onClick(DialogInterface dialog, int which) {
-            finish();
-          }
-        });
-        return builder.create();
-      case DIALOG_GET_DIRNAME:
-        final EditText dirName = new EditText(getBaseContext());
-        builder.setView(dirName);
-        builder.setTitle(R.string.uploader_info_dirname);
-        String pathToUpload;
-        if (mParents.empty()) {
-          pathToUpload = "/";
-        } else {
-          mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, mParents.peek()), 
-                                 null,
-                                 null,
-                                 null,
-                                 null);
-          mCursor.moveToFirst();
-          pathToUpload = mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_PATH)) +
-                         mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_NAME)).replace(" ", "%20");
-        }
-        a a = new a(pathToUpload, dirName);
-        builder.setPositiveButton(R.string.common_ok, a);
-        builder.setNegativeButton(R.string.common_cancel, new OnClickListener() {
-          public void onClick(DialogInterface dialog, int which) {
-            dialog.cancel();
-          }
-        });
-        return builder.create();
-      case DIALOG_MULTIPLE_ACCOUNT:
-        CharSequence ac[] = new CharSequence[mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE).length];
-        for (int i = 0;  i < ac.length; ++i) {
-          ac[i] = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE)[i].name;
-        }
-        builder.setTitle(R.string.common_choose_account);
-        builder.setItems(ac, new OnClickListener() {
-          public void onClick(DialogInterface dialog, int which) {
-            mAccount = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE)[which];
-            populateDirectoryList();
-          }
-        });
-        builder.setCancelable(true);
-        builder.setOnCancelListener(new OnCancelListener() {
-          public void onCancel(DialogInterface dialog) {
-            dialog.cancel();
-            finish();
-          }
-        });
-        return builder.create();
-      default:
-        throw new IllegalArgumentException("Unknown dialog id: " + id);
-    }
-  }
-  
-  class a implements OnClickListener {
-    String mPath;
-    EditText mDirname;
-    public a(String path, EditText dirname) {
-      mPath = path; mDirname = dirname;
-    }
-    public void onClick(DialogInterface dialog, int which) {
-      showDialog(DIALOG_WAITING);
-      mUploadThread = new Thread(new BackgroundUploader(mPath+mDirname.getText().toString(), mStreamsToUpload, mHandler, true));
-      mUploadThread.start();
-    }
-  }
-  
-  @Override
-  public void onBackPressed() {
-    
-    if (mParents.size()==0) {
-      super.onBackPressed();
-      return;
-    } else if (mParents.size() == 1) {
-      mParents.pop();
-      mCursor = managedQuery(ProviderTableMeta.CONTENT_URI,
-          null,
-          ProviderTableMeta.FILE_CONTENT_TYPE+"=?",
-          new String[]{"DIR"},
-          null);
-    } else {
-      mParents.pop();
-      mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_DIR, mParents.peek()),
-          null,
-          ProviderTableMeta.FILE_CONTENT_TYPE+"=?",
-          new String[]{"DIR"},
-          null);
-    }
-    
-    SimpleCursorAdapter sca = new SimpleCursorAdapter(this, R.layout.uploader_list_item_layout,
-                                   mCursor,
-                                   new String[]{ProviderTableMeta.FILE_NAME},
-                                   new int[]{R.id.textView1});
-    setListAdapter(sca);
-  }
-  
-  public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
-    if (!mCursor.moveToPosition(position)) {
-      throw new IndexOutOfBoundsException("Incorrect item selected");
-    }
-    String _id = mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta._ID));
-    mParents.push(_id);
-    
-    mCursor.close();
-    mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_DIR, _id),
-                           null,
-                           ProviderTableMeta.FILE_CONTENT_TYPE+"=?",
-                           new String[]{"DIR"},
-                           null);
-    SimpleCursorAdapter sca = new SimpleCursorAdapter(this, R.layout.uploader_list_item_layout,
-                                                      mCursor,
-                                                      new String[]{ProviderTableMeta.FILE_NAME},
-                                                      new int[]{R.id.textView1});
-    setListAdapter(sca);
-    getListView().invalidate();
-  }
-
-  public void onClick(View v) {
-    switch (v.getId()) {
-      case R.id.uploader_choose_folder:
-        String pathToUpload = null;
-        if (mParents.empty()) {
-          pathToUpload = "/";
-        } else {
-          mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, mParents.peek()), 
-                                 null,
-                                 null,
-                                 null,
-                                 null);
-          mCursor.moveToFirst();
-          pathToUpload = mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_PATH)) +
-                         mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_NAME)).replace(" ", "%20");
-        }
-        
-        showDialog(DIALOG_WAITING);
-        mUploadThread = new Thread(new BackgroundUploader(pathToUpload, mStreamsToUpload, mHandler));
-        mUploadThread.start();
-        
-        break;
-      case android.R.id.button1: // dynamic action for create aditional dir
-        showDialog(DIALOG_GET_DIRNAME);
-        break;
-      default:
-        throw new IllegalArgumentException("Wrong element clicked");
-    }
-  }
-
-  public void onUploadComplete(boolean uploadSucc, String message) {
-    dismissDialog(DIALOG_WAITING);
-    Log.i(TAG, "UploadSucc: " + uploadSucc + " message: " + message);
-    if (uploadSucc) {
-      Toast.makeText(this, getResources().getString(R.string.uploader_upload_succeed), Toast.LENGTH_SHORT).show();
-    } else {
-      Toast.makeText(this, getResources().getString(R.string.uploader_upload_failed) + message, Toast.LENGTH_LONG).show();
-    }
-    finish();
-  }
-  
-  @Override
-  protected void onActivityResult(int requestCode, int resultCode, Intent data) {
-    super.onActivityResult(requestCode, resultCode, data);
-    Log.i(TAG, "result received. req: " + requestCode + " res: " + resultCode);
-    if (requestCode == REQUEST_CODE_SETUP_ACCOUNT) {
-      dismissDialog(DIALOG_NO_ACCOUNT);
-      if (resultCode == RESULT_CANCELED) {
-        finish();
-      }
-      Account[] accounts = mAccountManager.getAccountsByType(AccountAuthenticator.AUTH_TOKEN_TYPE);
-      if (accounts.length == 0) {
-        showDialog(DIALOG_NO_ACCOUNT);
-      } else {
-        // there is no need for checking for is there more then one account at this point
-        // since account setup can set only one account at time
-        mAccount = accounts[0];
-        populateDirectoryList();
-      }
-    }
-  }
-  
-  private void populateDirectoryList() {
-    mUsername = mAccount.name.substring(0, mAccount.name.indexOf('@'));
-    mPassword = mAccountManager.getPassword(mAccount);
-    setContentView(R.layout.uploader_layout);
-    mCursor = managedQuery(ProviderMeta.ProviderTableMeta.CONTENT_URI,
-                           null,
-                           ProviderTableMeta.FILE_CONTENT_TYPE+"=? AND " + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?",
-                           new String[]{"DIR", mAccount.name},
-                           null);
-
-    ListView lv = getListView();
-    lv.setOnItemClickListener(this);
-    SimpleCursorAdapter sca = new SimpleCursorAdapter(this,
-                                                      R.layout.uploader_list_item_layout,
-                                                      mCursor,
-                                                      new String[]{ProviderTableMeta.FILE_NAME},
-                                                      new int[]{R.id.textView1});
-    setListAdapter(sca);
-    Button btn = (Button) findViewById(R.id.uploader_choose_folder);
-    btn.setOnClickListener(this);
-    // insert create new directory for multiple items uploading
-    if (getIntent().getAction().equals(Intent.ACTION_SEND_MULTIPLE)) {
-      Button createDirBtn = new Button(this);
-      createDirBtn.setId(android.R.id.button1);
-      createDirBtn.setText(R.string.uploader_btn_create_dir_text);
-      createDirBtn.setOnClickListener(this);
-      ((LinearLayout)findViewById(R.id.linearLayout1)).addView(createDirBtn, LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
-    }
-  }
-  
-  private void prepareStreamsToUpload() {
-    if (getIntent().getAction().equals(Intent.ACTION_SEND)) {
-      mStreamsToUpload = new ArrayList<Parcelable>();
-      mStreamsToUpload.add(getIntent().getParcelableExtra(Intent.EXTRA_STREAM));
-    } else if (getIntent().getAction().equals(Intent.ACTION_SEND_MULTIPLE)) {
-      mStreamsToUpload = getIntent().getParcelableArrayListExtra(Intent.EXTRA_STREAM);
-    } else {
-      // unknow action inserted
-      throw new IllegalArgumentException("Unknown action given: " + getIntent().getAction());
-    }
-  }
-  
-  public void PartialupdateUpload(String fileLocalPath, String filename, String filepath, String contentType, String contentLength) {
-    ContentValues cv = new ContentValues();
-    cv.put(ProviderTableMeta.FILE_NAME, filename);
-    cv.put(ProviderTableMeta.FILE_PATH, filepath);
-    cv.put(ProviderTableMeta.FILE_STORAGE_PATH, fileLocalPath);
-    cv.put(ProviderTableMeta.FILE_MODIFIED, WebdavUtils.DISPLAY_DATE_FORMAT.format(new java.util.Date()));
-    cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, contentType);
-    cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, contentLength);
-    cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, mAccount.name);
-    Log.d(TAG, filename+" ++ "+filepath+" ++ " + contentLength + " ++ " + contentType + " ++ " + fileLocalPath);
-    if (!mParents.empty()) {
-      Cursor c = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, mParents.peek()),
-                              null,
-                              null,
-                              null,
-                              null);
-      c.moveToFirst();
-      cv.put(ProviderTableMeta.FILE_PARENT, c.getString(c.getColumnIndex(ProviderTableMeta._ID)));
-      c.close();
-    }
-    getContentResolver().insert(ProviderTableMeta.CONTENT_URI_FILE, cv);
-  }
-  
-  class BackgroundUploader implements Runnable {
-    private ArrayList<Parcelable> mUploadStreams;
-    private Handler mHandler;
-    private String mUploadPath;
-    private boolean mCreateDir;
-    
-    public BackgroundUploader(String pathToUpload, ArrayList<Parcelable> streamsToUpload,
-        Handler handler) {
-      mUploadStreams = streamsToUpload;
-      mHandler = handler;
-      mUploadPath = pathToUpload.replace(" ", "%20");
-      mCreateDir = false;
-    }
-
-    public BackgroundUploader(String pathToUpload, ArrayList<Parcelable> streamsToUpload,
-                              Handler handler, boolean createDir) {
-      mUploadStreams = streamsToUpload;
-      mHandler = handler;
-      mUploadPath = pathToUpload.replace(" ", "%20");
-      mCreateDir = createDir;
-    }
-
-    public void run() {
-      WebdavClient wdc = new WebdavClient(Uri.parse(mAccountManager.getUserData(mAccount,
-          AccountAuthenticator.KEY_OC_URL)));
-      wdc.setCredentials(mUsername, mPassword);
-      wdc.allowUnsignedCertificates();
-
-      // create last directory in path if nessesary
-      if (mCreateDir) {
-        wdc.createDirectory(mUploadPath);
-      }
-      
-      for (int i = 0; i < mUploadStreams.size(); ++i) {
-        Uri uri = (Uri) mUploadStreams.get(i);
-        if (uri.getScheme().equals("content")) {
-          final Cursor c = getContentResolver().query((Uri) mUploadStreams.get(i), null, null, null, null);
-          c.moveToFirst();
-          
-          if (!wdc.putFile(c.getString(c.getColumnIndex(Media.DATA)),
-                           mUploadPath+"/"+c.getString(c.getColumnIndex(Media.DISPLAY_NAME)),
-                           c.getString(c.getColumnIndex(Media.MIME_TYPE)))) {
-            mHandler.post(new Runnable() {
-              public void run() {
-                Uploader.this.onUploadComplete(false, "Error while uploading file: " + c.getString(c.getColumnIndex(Media.DISPLAY_NAME)));
-              }
-            });
-          }
-        } else if (uri.getScheme().equals("file")) {
-         final File file = new File(Uri.decode(uri.toString()).replace(uri.getScheme()+"://", ""));
-         FileNameMap fileNameMap = URLConnection.getFileNameMap();
-         String contentType = fileNameMap.getContentTypeFor(uri.toString());
-         if (contentType == null) {
-           contentType = "text/plain";
-         }
-         if (!wdc.putFile(file.getAbsolutePath(), mUploadPath+"/"+file.getName(), contentType)) {
-           mHandler.post(new Runnable() {
-             public void run() {
-               Uploader.this.onUploadComplete(false, "Error while uploading file: " + file.getName());
-             }
-           });
-         }
-        }
-        
-      }
-      mHandler.post(new Runnable() {
-        public void run() {
-          Uploader.this.onUploadComplete(true, null);
-        }
-      });
-    }
-
-  }
-  
-}
+/* ownCloud Android client application
+ *   Copyright (C) 2011  Bartek Przybylski
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package eu.alefzero.owncloud;
+
+import java.io.File;
+import java.net.FileNameMap;
+import java.net.URI;
+import java.net.URLConnection;
+import java.util.ArrayList;
+import java.util.Stack;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.ListActivity;
+import android.app.ProgressDialog;
+import android.app.AlertDialog.Builder;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.DialogInterface.OnCancelListener;
+import android.content.DialogInterface.OnClickListener;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Parcelable;
+import android.provider.MediaStore.Images.Media;
+import android.util.Log;
+import android.view.View;
+import android.view.Window;
+import android.view.ViewGroup.LayoutParams;
+import android.widget.AdapterView;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.ListView;
+import android.widget.SimpleCursorAdapter;
+import android.widget.Toast;
+import android.widget.AdapterView.OnItemClickListener;
+import eu.alefzero.owncloud.authenticator.AccountAuthenticator;
+import eu.alefzero.owncloud.db.ProviderMeta;
+import eu.alefzero.owncloud.db.ProviderMeta.ProviderTableMeta;
+import eu.alefzero.webdav.WebdavClient;
+import eu.alefzero.webdav.WebdavUtils;
+
+/**
+ * This can be used to upload things to an ownCloud instance.
+ * @author Bartek Przybylski
+ *
+ */
+public class Uploader extends ListActivity implements OnItemClickListener, android.view.View.OnClickListener {
+  private static final String TAG = "ownCloudUploader";
+
+  private Account mAccount;
+  private AccountManager mAccountManager;
+  private String mUsername, mPassword;
+  private Cursor mCursor;
+  private Stack<String> mParents;
+  private Thread mUploadThread;
+  private Handler mHandler;
+  private ArrayList<Parcelable> mStreamsToUpload;
+
+  private final static int DIALOG_NO_ACCOUNT = 0;
+  private final static int DIALOG_WAITING = 1;
+  private final static int DIALOG_NO_STREAM = 2;
+  private final static int DIALOG_MULTIPLE_ACCOUNT = 3;
+  private final static int DIALOG_GET_DIRNAME = 4;
+
+  private final static int REQUEST_CODE_SETUP_ACCOUNT = 0;
+
+  @Override
+  protected void onCreate(Bundle savedInstanceState) {
+    super.onCreate(savedInstanceState);
+    getWindow().requestFeature(Window.FEATURE_NO_TITLE);
+    mParents = new Stack<String>();
+    mHandler = new Handler();
+    if (getIntent().hasExtra(Intent.EXTRA_STREAM)) {
+      prepareStreamsToUpload();
+      mAccountManager = (AccountManager)getSystemService(Context.ACCOUNT_SERVICE);
+      Account[] accounts = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE);
+      if (accounts.length == 0) {
+        Log.i(TAG, "No ownCloud account is available");
+        showDialog(DIALOG_NO_ACCOUNT);
+      } else if (accounts.length > 1) {
+        Log.i(TAG, "More then one ownCloud is available");
+        showDialog(DIALOG_MULTIPLE_ACCOUNT);
+      } else {
+        mAccount = accounts[0];
+        setContentView(R.layout.uploader_layout);
+        populateDirectoryList();
+      }
+    } else {
+      showDialog(DIALOG_NO_STREAM);
+    }
+  }
+
+  @Override
+  protected Dialog onCreateDialog(final int id) {
+    final AlertDialog.Builder builder = new Builder(this);
+    switch (id) {
+      case DIALOG_WAITING:
+        ProgressDialog pDialog = new ProgressDialog(this);
+        pDialog.setIndeterminate(false);
+        pDialog.setCancelable(false);
+        pDialog.setMessage(getResources().getString(R.string.uploader_info_uploading));
+        return pDialog;
+      case DIALOG_NO_ACCOUNT:
+        builder.setIcon(android.R.drawable.ic_dialog_alert);
+        builder.setTitle(R.string.uploader_wrn_no_account_title);
+        builder.setMessage(R.string.uploader_wrn_no_account_text);
+        builder.setCancelable(false);
+        builder.setPositiveButton(R.string.uploader_wrn_no_account_setup_btn_text, new OnClickListener() {
+          public void onClick(DialogInterface dialog, int which) {
+            if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.ECLAIR_MR1) {
+              // using string value since in API7 this constatn is not defined
+              // in API7 < this constatant is defined in Settings.ADD_ACCOUNT_SETTINGS
+              // and Settings.EXTRA_AUTHORITIES
+              Intent intent = new Intent("android.settings.ADD_ACCOUNT_SETTINGS");
+              intent.putExtra("authorities", new String[] {AccountAuthenticator.AUTH_TOKEN_TYPE});
+              startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT);
+            } else {
+              // since in API7 there is no direct call for account setup, so we need to
+              // show our own AccountSetupAcricity, get desired results and setup
+              // everything for ourself
+              Intent intent = new Intent(getBaseContext(), AccountAuthenticator.class);
+              startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT);
+            }
+          }
+        });
+        builder.setNegativeButton(R.string.uploader_wrn_no_account_quit_btn_text, new OnClickListener() {
+          public void onClick(DialogInterface dialog, int which) {
+            finish();
+          }
+        });
+        return builder.create();
+      case DIALOG_GET_DIRNAME:
+        final EditText dirName = new EditText(getBaseContext());
+        builder.setView(dirName);
+        builder.setTitle(R.string.uploader_info_dirname);
+        String pathToUpload;
+        if (mParents.empty()) {
+          pathToUpload = "/";
+        } else {
+          mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, mParents.peek()), 
+                                 null,
+                                 null,
+                                 null,
+                                 null);
+          mCursor.moveToFirst();
+          pathToUpload = mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_PATH)) +
+                         mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_NAME)).replace(" ", "%20");
+        }
+        a a = new a(pathToUpload, dirName);
+        builder.setPositiveButton(R.string.common_ok, a);
+        builder.setNegativeButton(R.string.common_cancel, new OnClickListener() {
+          public void onClick(DialogInterface dialog, int which) {
+            dialog.cancel();
+          }
+        });
+        return builder.create();
+      case DIALOG_MULTIPLE_ACCOUNT:
+        CharSequence ac[] = new CharSequence[mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE).length];
+        for (int i = 0;  i < ac.length; ++i) {
+          ac[i] = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE)[i].name;
+        }
+        builder.setTitle(R.string.common_choose_account);
+        builder.setItems(ac, new OnClickListener() {
+          public void onClick(DialogInterface dialog, int which) {
+            mAccount = mAccountManager.getAccountsByType(AccountAuthenticator.ACCOUNT_TYPE)[which];
+            populateDirectoryList();
+          }
+        });
+        builder.setCancelable(true);
+        builder.setOnCancelListener(new OnCancelListener() {
+          public void onCancel(DialogInterface dialog) {
+            dialog.cancel();
+            finish();
+          }
+        });
+        return builder.create();
+      default:
+        throw new IllegalArgumentException("Unknown dialog id: " + id);
+    }
+  }
+  
+  class a implements OnClickListener {
+    String mPath;
+    EditText mDirname;
+    public a(String path, EditText dirname) {
+      mPath = path; mDirname = dirname;
+    }
+    public void onClick(DialogInterface dialog, int which) {
+      showDialog(DIALOG_WAITING);
+      mUploadThread = new Thread(new BackgroundUploader(mPath+mDirname.getText().toString(), mStreamsToUpload, mHandler, true));
+      mUploadThread.start();
+    }
+  }
+  
+  @Override
+  public void onBackPressed() {
+    
+    if (mParents.size()==0) {
+      super.onBackPressed();
+      return;
+    } else if (mParents.size() == 1) {
+      mParents.pop();
+      mCursor = managedQuery(ProviderTableMeta.CONTENT_URI,
+          null,
+          ProviderTableMeta.FILE_CONTENT_TYPE+"=?",
+          new String[]{"DIR"},
+          null);
+    } else {
+      mParents.pop();
+      mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_DIR, mParents.peek()),
+          null,
+          ProviderTableMeta.FILE_CONTENT_TYPE+"=?",
+          new String[]{"DIR"},
+          null);
+    }
+    
+    SimpleCursorAdapter sca = new SimpleCursorAdapter(this, R.layout.uploader_list_item_layout,
+                                   mCursor,
+                                   new String[]{ProviderTableMeta.FILE_NAME},
+                                   new int[]{R.id.textView1});
+    setListAdapter(sca);
+  }
+  
+  public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+    if (!mCursor.moveToPosition(position)) {
+      throw new IndexOutOfBoundsException("Incorrect item selected");
+    }
+    String _id = mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta._ID));
+    mParents.push(_id);
+    
+    mCursor.close();
+    mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_DIR, _id),
+                           null,
+                           ProviderTableMeta.FILE_CONTENT_TYPE+"=?",
+                           new String[]{"DIR"},
+                           null);
+    SimpleCursorAdapter sca = new SimpleCursorAdapter(this, R.layout.uploader_list_item_layout,
+                                                      mCursor,
+                                                      new String[]{ProviderTableMeta.FILE_NAME},
+                                                      new int[]{R.id.textView1});
+    setListAdapter(sca);
+    getListView().invalidate();
+  }
+
+  public void onClick(View v) {
+    switch (v.getId()) {
+      case R.id.uploader_choose_folder:
+        String pathToUpload = null;
+        if (mParents.empty()) {
+          pathToUpload = "/";
+        } else {
+          mCursor = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, mParents.peek()), 
+                                 null,
+                                 null,
+                                 null,
+                                 null);
+          mCursor.moveToFirst();
+          pathToUpload = mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_PATH)) +
+                         mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_NAME)).replace(" ", "%20");
+        }
+        
+        showDialog(DIALOG_WAITING);
+        mUploadThread = new Thread(new BackgroundUploader(pathToUpload, mStreamsToUpload, mHandler));
+        mUploadThread.start();
+        
+        break;
+      case android.R.id.button1: // dynamic action for create aditional dir
+        showDialog(DIALOG_GET_DIRNAME);
+        break;
+      default:
+        throw new IllegalArgumentException("Wrong element clicked");
+    }
+  }
+
+  public void onUploadComplete(boolean uploadSucc, String message) {
+    dismissDialog(DIALOG_WAITING);
+    Log.i(TAG, "UploadSucc: " + uploadSucc + " message: " + message);
+    if (uploadSucc) {
+      Toast.makeText(this, getResources().getString(R.string.uploader_upload_succeed), Toast.LENGTH_SHORT).show();
+    } else {
+      Toast.makeText(this, getResources().getString(R.string.uploader_upload_failed) + message, Toast.LENGTH_LONG).show();
+    }
+    finish();
+  }
+  
+  @Override
+  protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+    super.onActivityResult(requestCode, resultCode, data);
+    Log.i(TAG, "result received. req: " + requestCode + " res: " + resultCode);
+    if (requestCode == REQUEST_CODE_SETUP_ACCOUNT) {
+      dismissDialog(DIALOG_NO_ACCOUNT);
+      if (resultCode == RESULT_CANCELED) {
+        finish();
+      }
+      Account[] accounts = mAccountManager.getAccountsByType(AccountAuthenticator.AUTH_TOKEN_TYPE);
+      if (accounts.length == 0) {
+        showDialog(DIALOG_NO_ACCOUNT);
+      } else {
+        // there is no need for checking for is there more then one account at this point
+        // since account setup can set only one account at time
+        mAccount = accounts[0];
+        populateDirectoryList();
+      }
+    }
+  }
+  
+  private void populateDirectoryList() {
+    mUsername = mAccount.name.substring(0, mAccount.name.indexOf('@'));
+    mPassword = mAccountManager.getPassword(mAccount);
+    setContentView(R.layout.uploader_layout);
+    mCursor = managedQuery(ProviderMeta.ProviderTableMeta.CONTENT_URI,
+                           null,
+                           ProviderTableMeta.FILE_CONTENT_TYPE+"=? AND " + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?",
+                           new String[]{"DIR", mAccount.name},
+                           null);
+
+    ListView lv = getListView();
+    lv.setOnItemClickListener(this);
+    SimpleCursorAdapter sca = new SimpleCursorAdapter(this,
+                                                      R.layout.uploader_list_item_layout,
+                                                      mCursor,
+                                                      new String[]{ProviderTableMeta.FILE_NAME},
+                                                      new int[]{R.id.textView1});
+    setListAdapter(sca);
+    Button btn = (Button) findViewById(R.id.uploader_choose_folder);
+    btn.setOnClickListener(this);
+    // insert create new directory for multiple items uploading
+    if (getIntent().getAction().equals(Intent.ACTION_SEND_MULTIPLE)) {
+      Button createDirBtn = new Button(this);
+      createDirBtn.setId(android.R.id.button1);
+      createDirBtn.setText(R.string.uploader_btn_create_dir_text);
+      createDirBtn.setOnClickListener(this);
+      ((LinearLayout)findViewById(R.id.linearLayout1)).addView(createDirBtn, LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
+    }
+  }
+  
+  private void prepareStreamsToUpload() {
+    if (getIntent().getAction().equals(Intent.ACTION_SEND)) {
+      mStreamsToUpload = new ArrayList<Parcelable>();
+      mStreamsToUpload.add(getIntent().getParcelableExtra(Intent.EXTRA_STREAM));
+    } else if (getIntent().getAction().equals(Intent.ACTION_SEND_MULTIPLE)) {
+      mStreamsToUpload = getIntent().getParcelableArrayListExtra(Intent.EXTRA_STREAM);
+    } else {
+      // unknow action inserted
+      throw new IllegalArgumentException("Unknown action given: " + getIntent().getAction());
+    }
+  }
+  
+  public void PartialupdateUpload(String fileLocalPath, String filename, String filepath, String contentType, String contentLength) {
+    ContentValues cv = new ContentValues();
+    cv.put(ProviderTableMeta.FILE_NAME, filename);
+    cv.put(ProviderTableMeta.FILE_PATH, filepath);
+    cv.put(ProviderTableMeta.FILE_STORAGE_PATH, fileLocalPath);
+    cv.put(ProviderTableMeta.FILE_MODIFIED, WebdavUtils.DISPLAY_DATE_FORMAT.format(new java.util.Date()));
+    cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, contentType);
+    cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, contentLength);
+    cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, mAccount.name);
+    Log.d(TAG, filename+" ++ "+filepath+" ++ " + contentLength + " ++ " + contentType + " ++ " + fileLocalPath);
+    if (!mParents.empty()) {
+      Cursor c = managedQuery(Uri.withAppendedPath(ProviderTableMeta.CONTENT_URI_FILE, mParents.peek()),
+                              null,
+                              null,
+                              null,
+                              null);
+      c.moveToFirst();
+      cv.put(ProviderTableMeta.FILE_PARENT, c.getString(c.getColumnIndex(ProviderTableMeta._ID)));
+      c.close();
+    }
+    getContentResolver().insert(ProviderTableMeta.CONTENT_URI_FILE, cv);
+  }
+  
+  class BackgroundUploader implements Runnable {
+    private ArrayList<Parcelable> mUploadStreams;
+    private Handler mHandler;
+    private String mUploadPath;
+    private boolean mCreateDir;
+    
+    public BackgroundUploader(String pathToUpload, ArrayList<Parcelable> streamsToUpload,
+        Handler handler) {
+      mUploadStreams = streamsToUpload;
+      mHandler = handler;
+      mUploadPath = pathToUpload.replace(" ", "%20");
+      mCreateDir = false;
+    }
+
+    public BackgroundUploader(String pathToUpload, ArrayList<Parcelable> streamsToUpload,
+                              Handler handler, boolean createDir) {
+      mUploadStreams = streamsToUpload;
+      mHandler = handler;
+      mUploadPath = pathToUpload.replace(" ", "%20");
+      mCreateDir = createDir;
+    }
+
+    public void run() {
+      WebdavClient wdc = new WebdavClient(Uri.parse(mAccountManager.getUserData(mAccount,
+          AccountAuthenticator.KEY_OC_URL)));
+      wdc.setCredentials(mUsername, mPassword);
+      wdc.allowUnsignedCertificates();
+
+      // create last directory in path if nessesary
+      if (mCreateDir) {
+        wdc.createDirectory(mUploadPath);
+      }
+      
+      for (int i = 0; i < mUploadStreams.size(); ++i) {
+        Uri uri = (Uri) mUploadStreams.get(i);
+        if (uri.getScheme().equals("content")) {
+          final Cursor c = getContentResolver().query((Uri) mUploadStreams.get(i), null, null, null, null);
+          c.moveToFirst();
+          
+          if (!wdc.putFile(c.getString(c.getColumnIndex(Media.DATA)),
+                           mUploadPath+"/"+c.getString(c.getColumnIndex(Media.DISPLAY_NAME)),
+                           c.getString(c.getColumnIndex(Media.MIME_TYPE)))) {
+            mHandler.post(new Runnable() {
+              public void run() {
+                Uploader.this.onUploadComplete(false, "Error while uploading file: " + c.getString(c.getColumnIndex(Media.DISPLAY_NAME)));
+              }
+            });
+          }
+        } else if (uri.getScheme().equals("file")) {
+         final File file = new File(Uri.decode(uri.toString()).replace(uri.getScheme()+"://", ""));
+         FileNameMap fileNameMap = URLConnection.getFileNameMap();
+         String contentType = fileNameMap.getContentTypeFor(uri.toString());
+         if (contentType == null) {
+           contentType = "text/plain";
+         }
+         if (!wdc.putFile(file.getAbsolutePath(), mUploadPath+"/"+file.getName(), contentType)) {
+           mHandler.post(new Runnable() {
+             public void run() {
+               Uploader.this.onUploadComplete(false, "Error while uploading file: " + file.getName());
+             }
+           });
+         }
+        }
+        
+      }
+      mHandler.post(new Runnable() {
+        public void run() {
+          Uploader.this.onUploadComplete(true, null);
+        }
+      });
+    }
+
+  }
+  
+}

+ 235 - 235
src/eu/alefzero/owncloud/authenticator/AccountAuthenticator.java

@@ -1,235 +1,235 @@
-package eu.alefzero.owncloud.authenticator;
-
-import eu.alefzero.owncloud.ui.AuthenticatorActivity;
-import android.accounts.*;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.util.Log;
-
-public class AccountAuthenticator extends AbstractAccountAuthenticator {
-    public static final String OPTIONS_USERNAME = "username";
-    public static final String OPTIONS_PASSWORD = "password";
-    public static final String OPTIONS_FILE_LIST_SYNC_ENABLED = "filelist";
-    public static final String OPTIONS_PINNED_FILE_SYNC_ENABLED = "pinned";
-
-    public static final String ACCOUNT_TYPE = "owncloud";
-    public static final String AUTH_TOKEN_TYPE = "org.owncloud";
-
-    public static final String KEY_AUTH_TOKEN_TYPE = "authTokenType";
-    public static final String KEY_REQUIRED_FEATURES = "requiredFeatures";
-    public static final String KEY_LOGIN_OPTIONS = "loginOptions";
-    public static final String KEY_ACCOUNT = "account";
-    public static final String KEY_OC_URL = "oc_url";
-    public static final String KEY_CONTACT_URL = "oc_contact_url";
-
-    private Context mContext;
-
-    public AccountAuthenticator(Context context) {
-        super(context);
-        mContext = context;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public Bundle addAccount(AccountAuthenticatorResponse response,
-                             String accountType, String authTokenType, String[] requiredFeatures,
-                             Bundle options) throws NetworkErrorException {
-        Log.i(getClass().getName(), "Adding account with type " + accountType +
-                " and auth token " + authTokenType);
-        try {
-            validateAccountType(accountType);
-            //validateAuthTokenType(authTokenType);
-            validateRequiredFeatures(requiredFeatures);
-        } catch (AuthenticatorException e) {
-            e.printStackTrace();
-            return e.getFailureBundle();
-        }
-        final Intent intent = new Intent(mContext, AuthenticatorActivity.class);
-        intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
-        intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType);
-        intent.putExtra(KEY_REQUIRED_FEATURES, requiredFeatures);
-        intent.putExtra(KEY_LOGIN_OPTIONS, options);
-
-        setIntentFlags(intent);
-        Log.i(getClass().getName(), intent.toString());
-        final Bundle bundle = new Bundle();
-        bundle.putParcelable(AccountManager.KEY_INTENT, intent);
-        return bundle;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public Bundle confirmCredentials(AccountAuthenticatorResponse response,
-                                     Account account, Bundle options) throws NetworkErrorException {
-        try {
-            validateAccountType(account.type);
-        } catch (AuthenticatorException e) {
-            return e.getFailureBundle();
-        }
-        Intent intent = new Intent(mContext, AuthenticatorActivity.class);
-        intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
-        intent.putExtra(KEY_ACCOUNT, account);
-        intent.putExtra(KEY_LOGIN_OPTIONS, options);
-
-        setIntentFlags(intent);
-
-        Bundle resultBundle = new Bundle();
-        resultBundle.putParcelable(AccountManager.KEY_INTENT, intent);
-        return resultBundle;
-    }
-
-    @Override
-    public Bundle editProperties(AccountAuthenticatorResponse response,
-                                 String accountType) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public Bundle getAuthToken(AccountAuthenticatorResponse response,
-                               Account account, String authTokenType, Bundle options)
-            throws NetworkErrorException {
-        Log.i(getClass().getName(), "Getting authToken");
-        try {
-            validateAccountType(account.type);
-            validateAuthTokenType(authTokenType);
-        } catch (AuthenticatorException e) {
-            Log.w(getClass().getName(), "Validating failded in getAuthToken");
-            return e.getFailureBundle();
-        }
-        final AccountManager am = AccountManager.get(mContext);
-        final String password = am.getPassword(account);
-        if (password != null) {
-            final Bundle result = new Bundle();
-            result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
-            result.putString(AccountManager.KEY_ACCOUNT_TYPE, ACCOUNT_TYPE);
-            result.putString(AccountManager.KEY_AUTHTOKEN, password);
-            return result;
-        }
-
-        final Intent intent = new Intent(mContext, AuthenticatorActivity.class);
-        intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
-        intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType);
-        intent.putExtra(KEY_LOGIN_OPTIONS, options);
-        intent.putExtra(AuthenticatorActivity.PARAM_USERNAME, account.name);
-
-        final Bundle bundle = new Bundle();
-        bundle.putParcelable(AccountManager.KEY_INTENT, intent);
-        return bundle;
-    }
-
-    @Override
-    public String getAuthTokenLabel(String authTokenType) {
-        return null;
-    }
-
-    @Override
-    public Bundle hasFeatures(AccountAuthenticatorResponse response,
-                              Account account, String[] features) throws NetworkErrorException {
-        final Bundle result = new Bundle();
-        result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);
-        return result;
-    }
-
-    @Override
-    public Bundle updateCredentials(AccountAuthenticatorResponse response,
-                                    Account account, String authTokenType, Bundle options)
-            throws NetworkErrorException {
-        final Intent intent = new Intent(mContext, AuthenticatorActivity.class);
-        intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
-        intent.putExtra(KEY_ACCOUNT, account);
-        intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType);
-        intent.putExtra(KEY_LOGIN_OPTIONS, options);
-        setIntentFlags(intent);
-
-        final Bundle bundle = new Bundle();
-        bundle.putParcelable(AccountManager.KEY_INTENT, intent);
-        return bundle;
-    }
-
-    @Override
-    public Bundle getAccountRemovalAllowed(AccountAuthenticatorResponse response,
-                                           Account account) throws NetworkErrorException {
-        return super.getAccountRemovalAllowed(response, account);
-    }
-
-    private void setIntentFlags(Intent intent) {
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
-        intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-        intent.addFlags(Intent.FLAG_FROM_BACKGROUND);
-    }
-
-    private void validateAccountType(String type) throws UnsupportedAccountTypeException {
-        if (!type.equals(ACCOUNT_TYPE)) {
-            throw new UnsupportedAccountTypeException();
-        }
-    }
-
-    private void validateAuthTokenType(String authTokenType) throws UnsupportedAuthTokenTypeException {
-        if (!authTokenType.equals(AUTH_TOKEN_TYPE)) {
-            throw new UnsupportedAuthTokenTypeException();
-        }
-    }
-
-    private void validateRequiredFeatures(String[] requiredFeatures) throws UnsupportedFeaturesException {
-        // TODO
-    }
-
-    private void validateCreaditials(String username, String password, String path) throws AccessDeniedException {
-
-    }
-
-    public static class AuthenticatorException extends Exception {
-        private static final long serialVersionUID = 1L;
-        private Bundle mFailureBundle;
-
-        public AuthenticatorException(int code, String errorMsg) {
-            mFailureBundle = new Bundle();
-            mFailureBundle.putInt(AccountManager.KEY_ERROR_CODE, code);
-            mFailureBundle.putString(AccountManager.KEY_ERROR_MESSAGE, errorMsg);
-        }
-
-        public Bundle getFailureBundle() {
-            return mFailureBundle;
-        }
-    }
-
-    public static class UnsupportedAccountTypeException extends AuthenticatorException {
-        private static final long serialVersionUID = 1L;
-
-        public UnsupportedAccountTypeException() {
-            super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION, "Unsupported account type");
-        }
-    }
-
-    public static class UnsupportedAuthTokenTypeException extends AuthenticatorException {
-        private static final long serialVersionUID = 1L;
-
-        public UnsupportedAuthTokenTypeException() {
-            super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION, "Unsupported auth token type");
-        }
-    }
-
-    public static class UnsupportedFeaturesException extends AuthenticatorException {
-        public static final long serialVersionUID = 1L;
-
-        public UnsupportedFeaturesException() {
-            super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION, "Unsupported features");
-        }
-    }
-
-    public static class AccessDeniedException extends AuthenticatorException {
-        public AccessDeniedException(int code, String errorMsg) {
-            super(AccountManager.ERROR_CODE_INVALID_RESPONSE, "Access Denied");
-        }
-
-        private static final long serialVersionUID = 1L;
-
-    }
-}
+package eu.alefzero.owncloud.authenticator;
+
+import eu.alefzero.owncloud.ui.activity.AuthenticatorActivity;
+import android.accounts.*;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+
+public class AccountAuthenticator extends AbstractAccountAuthenticator {
+    public static final String OPTIONS_USERNAME = "username";
+    public static final String OPTIONS_PASSWORD = "password";
+    public static final String OPTIONS_FILE_LIST_SYNC_ENABLED = "filelist";
+    public static final String OPTIONS_PINNED_FILE_SYNC_ENABLED = "pinned";
+
+    public static final String ACCOUNT_TYPE = "owncloud";
+    public static final String AUTH_TOKEN_TYPE = "org.owncloud";
+
+    public static final String KEY_AUTH_TOKEN_TYPE = "authTokenType";
+    public static final String KEY_REQUIRED_FEATURES = "requiredFeatures";
+    public static final String KEY_LOGIN_OPTIONS = "loginOptions";
+    public static final String KEY_ACCOUNT = "account";
+    public static final String KEY_OC_URL = "oc_url";
+    public static final String KEY_CONTACT_URL = "oc_contact_url";
+
+    private Context mContext;
+
+    public AccountAuthenticator(Context context) {
+        super(context);
+        mContext = context;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Bundle addAccount(AccountAuthenticatorResponse response,
+                             String accountType, String authTokenType, String[] requiredFeatures,
+                             Bundle options) throws NetworkErrorException {
+        Log.i(getClass().getName(), "Adding account with type " + accountType +
+                " and auth token " + authTokenType);
+        try {
+            validateAccountType(accountType);
+            //validateAuthTokenType(authTokenType);
+            validateRequiredFeatures(requiredFeatures);
+        } catch (AuthenticatorException e) {
+            e.printStackTrace();
+            return e.getFailureBundle();
+        }
+        final Intent intent = new Intent(mContext, AuthenticatorActivity.class);
+        intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
+        intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType);
+        intent.putExtra(KEY_REQUIRED_FEATURES, requiredFeatures);
+        intent.putExtra(KEY_LOGIN_OPTIONS, options);
+
+        setIntentFlags(intent);
+        Log.i(getClass().getName(), intent.toString());
+        final Bundle bundle = new Bundle();
+        bundle.putParcelable(AccountManager.KEY_INTENT, intent);
+        return bundle;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Bundle confirmCredentials(AccountAuthenticatorResponse response,
+                                     Account account, Bundle options) throws NetworkErrorException {
+        try {
+            validateAccountType(account.type);
+        } catch (AuthenticatorException e) {
+            return e.getFailureBundle();
+        }
+        Intent intent = new Intent(mContext, AuthenticatorActivity.class);
+        intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
+        intent.putExtra(KEY_ACCOUNT, account);
+        intent.putExtra(KEY_LOGIN_OPTIONS, options);
+
+        setIntentFlags(intent);
+
+        Bundle resultBundle = new Bundle();
+        resultBundle.putParcelable(AccountManager.KEY_INTENT, intent);
+        return resultBundle;
+    }
+
+    @Override
+    public Bundle editProperties(AccountAuthenticatorResponse response,
+                                 String accountType) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Bundle getAuthToken(AccountAuthenticatorResponse response,
+                               Account account, String authTokenType, Bundle options)
+            throws NetworkErrorException {
+        Log.i(getClass().getName(), "Getting authToken");
+        try {
+            validateAccountType(account.type);
+            validateAuthTokenType(authTokenType);
+        } catch (AuthenticatorException e) {
+            Log.w(getClass().getName(), "Validating failded in getAuthToken");
+            return e.getFailureBundle();
+        }
+        final AccountManager am = AccountManager.get(mContext);
+        final String password = am.getPassword(account);
+        if (password != null) {
+            final Bundle result = new Bundle();
+            result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
+            result.putString(AccountManager.KEY_ACCOUNT_TYPE, ACCOUNT_TYPE);
+            result.putString(AccountManager.KEY_AUTHTOKEN, password);
+            return result;
+        }
+
+        final Intent intent = new Intent(mContext, AuthenticatorActivity.class);
+        intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
+        intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType);
+        intent.putExtra(KEY_LOGIN_OPTIONS, options);
+        intent.putExtra(AuthenticatorActivity.PARAM_USERNAME, account.name);
+
+        final Bundle bundle = new Bundle();
+        bundle.putParcelable(AccountManager.KEY_INTENT, intent);
+        return bundle;
+    }
+
+    @Override
+    public String getAuthTokenLabel(String authTokenType) {
+        return null;
+    }
+
+    @Override
+    public Bundle hasFeatures(AccountAuthenticatorResponse response,
+                              Account account, String[] features) throws NetworkErrorException {
+        final Bundle result = new Bundle();
+        result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);
+        return result;
+    }
+
+    @Override
+    public Bundle updateCredentials(AccountAuthenticatorResponse response,
+                                    Account account, String authTokenType, Bundle options)
+            throws NetworkErrorException {
+        final Intent intent = new Intent(mContext, AuthenticatorActivity.class);
+        intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
+        intent.putExtra(KEY_ACCOUNT, account);
+        intent.putExtra(KEY_AUTH_TOKEN_TYPE, authTokenType);
+        intent.putExtra(KEY_LOGIN_OPTIONS, options);
+        setIntentFlags(intent);
+
+        final Bundle bundle = new Bundle();
+        bundle.putParcelable(AccountManager.KEY_INTENT, intent);
+        return bundle;
+    }
+
+    @Override
+    public Bundle getAccountRemovalAllowed(AccountAuthenticatorResponse response,
+                                           Account account) throws NetworkErrorException {
+        return super.getAccountRemovalAllowed(response, account);
+    }
+
+    private void setIntentFlags(Intent intent) {
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
+        intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+        intent.addFlags(Intent.FLAG_FROM_BACKGROUND);
+    }
+
+    private void validateAccountType(String type) throws UnsupportedAccountTypeException {
+        if (!type.equals(ACCOUNT_TYPE)) {
+            throw new UnsupportedAccountTypeException();
+        }
+    }
+
+    private void validateAuthTokenType(String authTokenType) throws UnsupportedAuthTokenTypeException {
+        if (!authTokenType.equals(AUTH_TOKEN_TYPE)) {
+            throw new UnsupportedAuthTokenTypeException();
+        }
+    }
+
+    private void validateRequiredFeatures(String[] requiredFeatures) throws UnsupportedFeaturesException {
+        // TODO
+    }
+
+    private void validateCreaditials(String username, String password, String path) throws AccessDeniedException {
+
+    }
+
+    public static class AuthenticatorException extends Exception {
+        private static final long serialVersionUID = 1L;
+        private Bundle mFailureBundle;
+
+        public AuthenticatorException(int code, String errorMsg) {
+            mFailureBundle = new Bundle();
+            mFailureBundle.putInt(AccountManager.KEY_ERROR_CODE, code);
+            mFailureBundle.putString(AccountManager.KEY_ERROR_MESSAGE, errorMsg);
+        }
+
+        public Bundle getFailureBundle() {
+            return mFailureBundle;
+        }
+    }
+
+    public static class UnsupportedAccountTypeException extends AuthenticatorException {
+        private static final long serialVersionUID = 1L;
+
+        public UnsupportedAccountTypeException() {
+            super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION, "Unsupported account type");
+        }
+    }
+
+    public static class UnsupportedAuthTokenTypeException extends AuthenticatorException {
+        private static final long serialVersionUID = 1L;
+
+        public UnsupportedAuthTokenTypeException() {
+            super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION, "Unsupported auth token type");
+        }
+    }
+
+    public static class UnsupportedFeaturesException extends AuthenticatorException {
+        public static final long serialVersionUID = 1L;
+
+        public UnsupportedFeaturesException() {
+            super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION, "Unsupported features");
+        }
+    }
+
+    public static class AccessDeniedException extends AuthenticatorException {
+        public AccessDeniedException(int code, String errorMsg) {
+            super(AccountManager.ERROR_CODE_INVALID_RESPONSE, "Access Denied");
+        }
+
+        private static final long serialVersionUID = 1L;
+
+    }
+}

+ 243 - 243
src/eu/alefzero/owncloud/authenticator/AuthUtils.java

@@ -1,243 +1,243 @@
-/* ownCloud Android client application
- *   Copyright (C) 2011  Bartek Przybylski
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation, either version 3 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-package eu.alefzero.owncloud.authenticator;
-
-import java.io.IOException;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.UnknownHostException;
-import java.security.KeyManagementException;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.SecureRandom;
-import java.security.UnrecoverableKeyException;
-
-import javax.net.SocketFactory;
-import javax.net.ssl.HostnameVerifier;
-import javax.net.ssl.HttpsURLConnection;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLSession;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.X509TrustManager;
-
-import javax.security.cert.CertificateException;
-import javax.security.cert.X509Certificate;
-
-import org.apache.http.client.HttpClient;
-import org.apache.http.conn.ClientConnectionManager;
-import org.apache.http.conn.scheme.Scheme;
-import org.apache.http.conn.scheme.SchemeRegistry;
-
-import org.apache.http.impl.client.DefaultHttpClient;
-
-import org.apache.commons.httpclient.auth.BasicScheme;
-import org.apache.http.HttpHost;
-import org.apache.http.HttpResponse;
-import org.apache.http.HttpVersion;
-import org.apache.http.auth.AuthScope;
-import org.apache.http.auth.UsernamePasswordCredentials;
-import org.apache.http.client.ClientProtocolException;
-import org.apache.http.client.methods.HttpHead;
-import org.apache.http.conn.params.ConnManagerPNames;
-import org.apache.http.conn.params.ConnPerRouteBean;
-import org.apache.http.conn.scheme.PlainSocketFactory;
-import org.apache.http.conn.ssl.SSLSocketFactory;
-import org.apache.http.impl.conn.SingleClientConnManager;
-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.BasicHttpContext;
-
-import eu.alefzero.owncloud.ui.AuthenticatorActivity;
-
-
-import android.content.Context;
-import android.os.Handler;
-import android.util.Log;
-
-public class AuthUtils {
-  public static final String WEBDAV_PATH_1_2 = "/webdav/owncloud.php";
-  public static final String WEBDAV_PATH_2_0 = "/files/webdav.php";
-  public static final String CARDDAV_PATH_2_0 = "/apps/contacts/carddav.php";
-  
-  private static String mResultMsg = "";
-  
-  public static boolean authenticate(URL url, String username, String password,
-                                     Handler handler, Context context) {
-    String strippedPath = url.toString().endsWith("/") ?
-                          url.toString().substring(0, url.toString().length()-1) :
-                          url.toString();
-    String webdatPath = strippedPath + WEBDAV_PATH_2_0;
-    URL complete_url = null;
-    try {
-      complete_url = new URL(webdatPath);
-    } catch (MalformedURLException e) {
-      // should never happend
-      sendResult(false, handler, context, "URL error");
-      return false;
-    }
-    
-    // version 2.0 success
-    if (tryGetWebdav(complete_url, username, password, handler, context)) {
-      sendResult(true, handler, context, complete_url.toString());
-      return true;
-    }
-    
-    if (mResultMsg.equals("401")) {
-       sendResult(false, handler, context, "Invalid login or/and password");
-       return false;
-    }
-    
-    if (!mResultMsg.equals("404")) {
-      sendResult(false, handler, context, "Server error: " + mResultMsg);
-      return false;
-    }
-    
-    webdatPath = strippedPath + WEBDAV_PATH_1_2;
-    try {
-      complete_url = new URL(webdatPath);
-    } catch (MalformedURLException e) {
-      // should never happend
-      sendResult(false, handler, context, "URL error");
-      return false;
-    }
-    
-    // version 1.2 success
-    if (tryGetWebdav(complete_url, username, password, handler, context)) {
-      sendResult(true, handler, context, complete_url.toString());
-      return true;
-    }
-    
-    if (mResultMsg.equals("401")) {
-      sendResult(false, handler, context, "Invalid login or/and password");
-      return false;
-    }
-    
-    if (mResultMsg.equals("404")) {
-      sendResult(false, handler, context, "Wrong path given");
-      return false;
-    }
-    
-    sendResult(false, handler, context, "Server error: " + mResultMsg);
-    return false;
-  }
-  
-  public static boolean tryGetWebdav(URL url, String username, String pwd,
-                                     Handler handler, Context context) {
-    SchemeRegistry schemeRegistry = new SchemeRegistry();
- // http scheme
- schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
- // https scheme
- schemeRegistry.register(new Scheme("https", new EasySSLSocketFactory(), 443));
-
- HttpParams params = new BasicHttpParams();
- params.setParameter(ConnManagerPNames.MAX_TOTAL_CONNECTIONS, 30);
- params.setParameter(ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE, new ConnPerRouteBean(30));
- params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, false);
- HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
-
- ClientConnectionManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);
-    
-    DefaultHttpClient c = new DefaultHttpClient(cm, params);
-    
-    c.getCredentialsProvider().setCredentials(
-        new AuthScope(url.getHost(), (url.getPort() == -1)?80:url.getPort()), 
-        new UsernamePasswordCredentials(username, pwd));
-    
-    BasicHttpContext localcontext  = new BasicHttpContext();
-    BasicScheme basicAuth = new BasicScheme();
-
-    localcontext.setAttribute("preemptive-auth", basicAuth);
-    HttpHost targetHost = new HttpHost(url.getHost(), (url.getPort() == -1)
-        ? 80
-        : url.getPort(), (url.getProtocol().equals("https")) ? "https" : "http");
-    HttpHead httpget = new HttpHead(url.toString());
-    httpget.setHeader("Host", url.getHost());
-    HttpResponse response = null;
-    try {
-      response = c.execute(targetHost, httpget, localcontext);
-    } catch (ClientProtocolException e1) {
-      sendResult(false, handler, context, "Protocol error: "
-          + e1.getLocalizedMessage());
-      return false;
-    } catch (UnknownHostException e1) {
-      mResultMsg = "Unknowh host: " + e1.getLocalizedMessage();
-      return false;
-    } catch (IOException e1) {
-      mResultMsg = "Error: " + e1.getLocalizedMessage();
-      return false;
-    }
-    String status = response.getStatusLine().toString();
-
-    status = status.split(" ")[1];
-    Log.i("AuthUtils", "Status returned: " + status);
-    if (status.equals("200")) {
-      return true;
-    } else if (status.equals("404")) {
-      mResultMsg = "404";
-      return false;
-    } else if (status.equals("401")) {
-      mResultMsg = "401";
-      return false;
-    }
-    mResultMsg = status;
-    return false;
-  }
-  
-  public static Thread performOnBackgroundThread(final Runnable r) {
-    final Thread t = new Thread() {
-      @Override
-      public void run() {
-        try {
-          r.run();
-        } finally {}
-      }
-    };
-    t.start();
-    return t;
-  }
-  
-  public static void sendResult(final Boolean result,
-                                final Handler handler,
-                                final Context context,
-                                final String message) {
-    if (handler == null || context == null) {
-      return;
-    }
-    handler.post(new Runnable() {
-      public void run() {
-        ((AuthenticatorActivity) context).onAuthenticationResult(result, message); 
-      }
-    });
-  }
-  
-  public static Thread attemptAuth(final URL url, final String username,
-                                   final String password, final Handler handler,
-                                   final Context context) {
-    final Runnable r = new Runnable() {
-      
-      public void run() {
-        authenticate(url, username, password, handler, context);
-      }
-    };
-    return performOnBackgroundThread(r);
-  }
-}
+/* ownCloud Android client application
+ *   Copyright (C) 2011  Bartek Przybylski
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package eu.alefzero.owncloud.authenticator;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.UnknownHostException;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.UnrecoverableKeyException;
+
+import javax.net.SocketFactory;
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+
+import javax.security.cert.CertificateException;
+import javax.security.cert.X509Certificate;
+
+import org.apache.http.client.HttpClient;
+import org.apache.http.conn.ClientConnectionManager;
+import org.apache.http.conn.scheme.Scheme;
+import org.apache.http.conn.scheme.SchemeRegistry;
+
+import org.apache.http.impl.client.DefaultHttpClient;
+
+import org.apache.commons.httpclient.auth.BasicScheme;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpVersion;
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.UsernamePasswordCredentials;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.methods.HttpHead;
+import org.apache.http.conn.params.ConnManagerPNames;
+import org.apache.http.conn.params.ConnPerRouteBean;
+import org.apache.http.conn.scheme.PlainSocketFactory;
+import org.apache.http.conn.ssl.SSLSocketFactory;
+import org.apache.http.impl.conn.SingleClientConnManager;
+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.BasicHttpContext;
+
+import eu.alefzero.owncloud.ui.activity.AuthenticatorActivity;
+
+
+import android.content.Context;
+import android.os.Handler;
+import android.util.Log;
+
+public class AuthUtils {
+  public static final String WEBDAV_PATH_1_2 = "/webdav/owncloud.php";
+  public static final String WEBDAV_PATH_2_0 = "/files/webdav.php";
+  public static final String CARDDAV_PATH_2_0 = "/apps/contacts/carddav.php";
+  
+  private static String mResultMsg = "";
+  
+  public static boolean authenticate(URL url, String username, String password,
+                                     Handler handler, Context context) {
+    String strippedPath = url.toString().endsWith("/") ?
+                          url.toString().substring(0, url.toString().length()-1) :
+                          url.toString();
+    String webdatPath = strippedPath + WEBDAV_PATH_2_0;
+    URL complete_url = null;
+    try {
+      complete_url = new URL(webdatPath);
+    } catch (MalformedURLException e) {
+      // should never happend
+      sendResult(false, handler, context, "URL error");
+      return false;
+    }
+    
+    // version 2.0 success
+    if (tryGetWebdav(complete_url, username, password, handler, context)) {
+      sendResult(true, handler, context, complete_url.toString());
+      return true;
+    }
+    
+    if (mResultMsg.equals("401")) {
+       sendResult(false, handler, context, "Invalid login or/and password");
+       return false;
+    }
+    
+    if (!mResultMsg.equals("404")) {
+      sendResult(false, handler, context, "Server error: " + mResultMsg);
+      return false;
+    }
+    
+    webdatPath = strippedPath + WEBDAV_PATH_1_2;
+    try {
+      complete_url = new URL(webdatPath);
+    } catch (MalformedURLException e) {
+      // should never happend
+      sendResult(false, handler, context, "URL error");
+      return false;
+    }
+    
+    // version 1.2 success
+    if (tryGetWebdav(complete_url, username, password, handler, context)) {
+      sendResult(true, handler, context, complete_url.toString());
+      return true;
+    }
+    
+    if (mResultMsg.equals("401")) {
+      sendResult(false, handler, context, "Invalid login or/and password");
+      return false;
+    }
+    
+    if (mResultMsg.equals("404")) {
+      sendResult(false, handler, context, "Wrong path given");
+      return false;
+    }
+    
+    sendResult(false, handler, context, "Server error: " + mResultMsg);
+    return false;
+  }
+  
+  public static boolean tryGetWebdav(URL url, String username, String pwd,
+                                     Handler handler, Context context) {
+    SchemeRegistry schemeRegistry = new SchemeRegistry();
+ // http scheme
+ schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
+ // https scheme
+ schemeRegistry.register(new Scheme("https", new EasySSLSocketFactory(), 443));
+
+ HttpParams params = new BasicHttpParams();
+ params.setParameter(ConnManagerPNames.MAX_TOTAL_CONNECTIONS, 30);
+ params.setParameter(ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE, new ConnPerRouteBean(30));
+ params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, false);
+ HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
+
+ ClientConnectionManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);
+    
+    DefaultHttpClient c = new DefaultHttpClient(cm, params);
+    
+    c.getCredentialsProvider().setCredentials(
+        new AuthScope(url.getHost(), (url.getPort() == -1)?80:url.getPort()), 
+        new UsernamePasswordCredentials(username, pwd));
+    
+    BasicHttpContext localcontext  = new BasicHttpContext();
+    BasicScheme basicAuth = new BasicScheme();
+
+    localcontext.setAttribute("preemptive-auth", basicAuth);
+    HttpHost targetHost = new HttpHost(url.getHost(), (url.getPort() == -1)
+        ? 80
+        : url.getPort(), (url.getProtocol().equals("https")) ? "https" : "http");
+    HttpHead httpget = new HttpHead(url.toString());
+    httpget.setHeader("Host", url.getHost());
+    HttpResponse response = null;
+    try {
+      response = c.execute(targetHost, httpget, localcontext);
+    } catch (ClientProtocolException e1) {
+      sendResult(false, handler, context, "Protocol error: "
+          + e1.getLocalizedMessage());
+      return false;
+    } catch (UnknownHostException e1) {
+      mResultMsg = "Unknowh host: " + e1.getLocalizedMessage();
+      return false;
+    } catch (IOException e1) {
+      mResultMsg = "Error: " + e1.getLocalizedMessage();
+      return false;
+    }
+    String status = response.getStatusLine().toString();
+
+    status = status.split(" ")[1];
+    Log.i("AuthUtils", "Status returned: " + status);
+    if (status.equals("200")) {
+      return true;
+    } else if (status.equals("404")) {
+      mResultMsg = "404";
+      return false;
+    } else if (status.equals("401")) {
+      mResultMsg = "401";
+      return false;
+    }
+    mResultMsg = status;
+    return false;
+  }
+  
+  public static Thread performOnBackgroundThread(final Runnable r) {
+    final Thread t = new Thread() {
+      @Override
+      public void run() {
+        try {
+          r.run();
+        } finally {}
+      }
+    };
+    t.start();
+    return t;
+  }
+  
+  public static void sendResult(final Boolean result,
+                                final Handler handler,
+                                final Context context,
+                                final String message) {
+    if (handler == null || context == null) {
+      return;
+    }
+    handler.post(new Runnable() {
+      public void run() {
+        ((AuthenticatorActivity) context).onAuthenticationResult(result, message); 
+      }
+    });
+  }
+  
+  public static Thread attemptAuth(final URL url, final String username,
+                                   final String password, final Handler handler,
+                                   final Context context) {
+    final Runnable r = new Runnable() {
+      
+      public void run() {
+        authenticate(url, username, password, handler, context);
+      }
+    };
+    return performOnBackgroundThread(r);
+  }
+}

+ 215 - 210
src/eu/alefzero/owncloud/cp.java

@@ -1,210 +1,215 @@
-/* ownCloud Android client application
- *   Copyright (C) 2011  Bartek Przybylski
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation, either version 3 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-package eu.alefzero.owncloud;
-
-import java.util.HashMap;
-
-import eu.alefzero.owncloud.db.ProviderMeta;
-import eu.alefzero.owncloud.db.ProviderMeta.ProviderTableMeta;
-
-import android.content.ContentProvider;
-import android.content.ContentUris;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.UriMatcher;
-import android.database.Cursor;
-import android.database.SQLException;
-import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteOpenHelper;
-import android.database.sqlite.SQLiteQueryBuilder;
-import android.net.Uri;
-import android.text.TextUtils;
-
-public class cp extends ContentProvider {
-
-  private DataBaseHelper mDbHelper;
-  
-  private static HashMap<String, String> mProjectionMap;
-  static {
-    mProjectionMap = new HashMap<String, String>();
-    mProjectionMap.put(ProviderTableMeta._ID,
-                       ProviderTableMeta._ID);
-    mProjectionMap.put(ProviderTableMeta.FILE_PARENT,
-                       ProviderTableMeta.FILE_PARENT);
-    mProjectionMap.put(ProviderTableMeta.FILE_PATH,
-                       ProviderTableMeta.FILE_PATH);
-    mProjectionMap.put(ProviderTableMeta.FILE_NAME,
-                       ProviderTableMeta.FILE_NAME);
-    mProjectionMap.put(ProviderTableMeta.FILE_CREATION,
-                       ProviderTableMeta.FILE_CREATION);
-    mProjectionMap.put(ProviderTableMeta.FILE_MODIFIED,
-                       ProviderTableMeta.FILE_MODIFIED);
-    mProjectionMap.put(ProviderTableMeta.FILE_CONTENT_LENGTH,
-                       ProviderTableMeta.FILE_CONTENT_LENGTH);
-    mProjectionMap.put(ProviderTableMeta.FILE_CONTENT_TYPE,
-                       ProviderTableMeta.FILE_CONTENT_TYPE);
-    mProjectionMap.put(ProviderTableMeta.FILE_STORAGE_PATH,
-                       ProviderTableMeta.FILE_STORAGE_PATH);
-  }
-  
-  private static final int SINGLE_FILE = 1;
-  private static final int DIRECTORY = 2;
-  private static final int ROOT_DIRECTORY = 3;
-  private static final UriMatcher mUriMatcher;
-  static {
-    mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
-    mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "/", ROOT_DIRECTORY);
-    mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "file/", SINGLE_FILE);
-    mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "file/#", SINGLE_FILE);
-    mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "dir/#", DIRECTORY);
-  }
-  
-  private static final String TAG = "OC_ContentProvider";
-  
-  @Override
-  public int delete(Uri uri, String where, String[] whereArgs) {
-    SQLiteDatabase db = mDbHelper.getWritableDatabase();
-    int count = 0;
-    switch (mUriMatcher.match(uri)) {
-      case SINGLE_FILE:
-        count = db.delete(ProviderTableMeta.DB_NAME,
-                          ProviderTableMeta._ID + "=" + uri.getPathSegments().get(1)
-                          + (!TextUtils.isEmpty(where)?" AND (" + where +")" : ""),
-                          whereArgs);
-        break;
-      case ROOT_DIRECTORY:
-        count = db.delete(ProviderTableMeta.DB_NAME, where, whereArgs);
-        break;
-      default:
-        throw new IllegalArgumentException("Unknown uri: " + uri.toString());
-    }
-    getContext().getContentResolver().notifyChange(uri, null);
-    return count;
-  }
-
-  @Override
-  public String getType(Uri uri) {
-    switch (mUriMatcher.match(uri)) {
-      case ROOT_DIRECTORY:
-        return ProviderTableMeta.CONTENT_TYPE;
-      case SINGLE_FILE:
-        return ProviderTableMeta.CONTENT_TYPE_ITEM;
-      default:
-        throw new IllegalArgumentException("Unknown Uri id." + uri.toString());
-    }
-  }
-
-  @Override
-  public Uri insert(Uri uri, ContentValues values) {
-    if (mUriMatcher.match(uri) != SINGLE_FILE) {
-      throw new IllegalArgumentException("Unknown uri id: " + uri);
-    }
-    
-    SQLiteDatabase db = mDbHelper.getWritableDatabase();
-    long rowId = db.insert(ProviderTableMeta.DB_NAME, ProviderTableMeta.FILE_NAME, values);
-    if (rowId > 0) {
-      Uri insertedFileUri = ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, rowId);
-      getContext().getContentResolver().notifyChange(insertedFileUri, null);
-      return insertedFileUri;
-    }
-    throw new SQLException("ERROR " + uri);
-  }
-
-  @Override
-  public boolean onCreate() {
-    mDbHelper = new DataBaseHelper(getContext());
-    return true;
-  }
-
-  @Override
-  public Cursor query(Uri uri, String[] projection, String selection,
-      String[] selectionArgs, String sortOrder) {
-    SQLiteQueryBuilder sqlQuery = new SQLiteQueryBuilder();
-        
-    sqlQuery.setTables(ProviderTableMeta.DB_NAME);
-    sqlQuery.setProjectionMap(mProjectionMap);
-    
-    switch (mUriMatcher.match(uri)) {
-      case ROOT_DIRECTORY:
-        sqlQuery.appendWhere(ProviderTableMeta.FILE_PARENT + " is null");
-        break;
-      case DIRECTORY:
-        sqlQuery.appendWhere(ProviderTableMeta.FILE_PARENT + "="+uri.getPathSegments().get(1));
-        break;
-      case SINGLE_FILE:
-        if (uri.getPathSegments().size() > 1) {
-          sqlQuery.appendWhere(ProviderTableMeta._ID + "=" +
-                               uri.getPathSegments().get(1));
-        }
-        break;
-      default:
-        throw new IllegalArgumentException("Unknown uri id: " + uri);
-    }
-    
-    String order;
-    if (TextUtils.isEmpty(sortOrder)) {
-      order = ProviderTableMeta.DEFAULT_SORT_ORDER;
-    } else {
-      order = sortOrder;
-    }
-    
-    SQLiteDatabase db = mDbHelper.getReadableDatabase();
-    Cursor c = sqlQuery.query(db, projection, selection, selectionArgs, null, null, order);
-    
-    c.setNotificationUri(getContext().getContentResolver(), uri);
-
-    return c;
-  }
-
-  @Override
-  public int update(Uri uri, ContentValues values, String selection,
-      String[] selectionArgs) {
-    return mDbHelper.getWritableDatabase().update(ProviderTableMeta.DB_NAME, values, selection, selectionArgs);
-  }
-
-  class DataBaseHelper extends SQLiteOpenHelper {
-
-    public DataBaseHelper(Context context) {
-      super(context, ProviderMeta.DB_NAME, null, ProviderMeta.DB_VERSION);
-      
-    }
-    
-    @Override
-    public void onCreate(SQLiteDatabase db) {
-      db.execSQL("CREATE TABLE " + ProviderTableMeta.DB_NAME + "(" +
-                 ProviderTableMeta._ID + " INTEGER PRIMARY KEY, " +
-                 ProviderTableMeta.FILE_NAME + " TEXT, " +
-                 ProviderTableMeta.FILE_PATH + " TEXT, " +
-                 ProviderTableMeta.FILE_PARENT + " INTEGER, " +
-                 ProviderTableMeta.FILE_CREATION + " INTEGER, " +
-                 ProviderTableMeta.FILE_MODIFIED + " INTEGER, " +
-                 ProviderTableMeta.FILE_CONTENT_TYPE + " TEXT, " +
-                 ProviderTableMeta.FILE_CONTENT_LENGTH + " INTEGER, " +
-                 ProviderTableMeta.FILE_STORAGE_PATH + " TEXT, " +
-                 ProviderTableMeta.FILE_ACCOUNT_OWNER + " TEXT);");
-    }
-
-    @Override
-    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
-      
-    }
-    
-  }
-  
-}
+/* ownCloud Android client application
+ *   Copyright (C) 2011  Bartek Przybylski
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package eu.alefzero.owncloud;
+
+import java.util.HashMap;
+
+import eu.alefzero.owncloud.db.ProviderMeta;
+import eu.alefzero.owncloud.db.ProviderMeta.ProviderTableMeta;
+
+import android.content.ContentProvider;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.UriMatcher;
+import android.database.Cursor;
+import android.database.SQLException;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.database.sqlite.SQLiteQueryBuilder;
+import android.net.Uri;
+import android.text.TextUtils;
+
+/**
+* The ContentProvider for the ownCloud App.
+* @author Bartek Przybylski
+* 
+*/
+public class cp extends ContentProvider {
+
+  private DataBaseHelper mDbHelper;
+  
+  private static HashMap<String, String> mProjectionMap;
+  static {
+    mProjectionMap = new HashMap<String, String>();
+    mProjectionMap.put(ProviderTableMeta._ID,
+                       ProviderTableMeta._ID);
+    mProjectionMap.put(ProviderTableMeta.FILE_PARENT,
+                       ProviderTableMeta.FILE_PARENT);
+    mProjectionMap.put(ProviderTableMeta.FILE_PATH,
+                       ProviderTableMeta.FILE_PATH);
+    mProjectionMap.put(ProviderTableMeta.FILE_NAME,
+                       ProviderTableMeta.FILE_NAME);
+    mProjectionMap.put(ProviderTableMeta.FILE_CREATION,
+                       ProviderTableMeta.FILE_CREATION);
+    mProjectionMap.put(ProviderTableMeta.FILE_MODIFIED,
+                       ProviderTableMeta.FILE_MODIFIED);
+    mProjectionMap.put(ProviderTableMeta.FILE_CONTENT_LENGTH,
+                       ProviderTableMeta.FILE_CONTENT_LENGTH);
+    mProjectionMap.put(ProviderTableMeta.FILE_CONTENT_TYPE,
+                       ProviderTableMeta.FILE_CONTENT_TYPE);
+    mProjectionMap.put(ProviderTableMeta.FILE_STORAGE_PATH,
+                       ProviderTableMeta.FILE_STORAGE_PATH);
+  }
+  
+  private static final int SINGLE_FILE = 1;
+  private static final int DIRECTORY = 2;
+  private static final int ROOT_DIRECTORY = 3;
+  private static final UriMatcher mUriMatcher;
+  static {
+    mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
+    mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "/", ROOT_DIRECTORY);
+    mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "file/", SINGLE_FILE);
+    mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "file/#", SINGLE_FILE);
+    mUriMatcher.addURI(ProviderMeta.AUTHORITY_FILES, "dir/#", DIRECTORY);
+  }
+  
+  private static final String TAG = "OC_ContentProvider";
+  
+  @Override
+  public int delete(Uri uri, String where, String[] whereArgs) {
+    SQLiteDatabase db = mDbHelper.getWritableDatabase();
+    int count = 0;
+    switch (mUriMatcher.match(uri)) {
+      case SINGLE_FILE:
+        count = db.delete(ProviderTableMeta.DB_NAME,
+                          ProviderTableMeta._ID + "=" + uri.getPathSegments().get(1)
+                          + (!TextUtils.isEmpty(where)?" AND (" + where +")" : ""),
+                          whereArgs);
+        break;
+      case ROOT_DIRECTORY:
+        count = db.delete(ProviderTableMeta.DB_NAME, where, whereArgs);
+        break;
+      default:
+        throw new IllegalArgumentException("Unknown uri: " + uri.toString());
+    }
+    getContext().getContentResolver().notifyChange(uri, null);
+    return count;
+  }
+
+  @Override
+  public String getType(Uri uri) {
+    switch (mUriMatcher.match(uri)) {
+      case ROOT_DIRECTORY:
+        return ProviderTableMeta.CONTENT_TYPE;
+      case SINGLE_FILE:
+        return ProviderTableMeta.CONTENT_TYPE_ITEM;
+      default:
+        throw new IllegalArgumentException("Unknown Uri id." + uri.toString());
+    }
+  }
+
+  @Override
+  public Uri insert(Uri uri, ContentValues values) {
+    if (mUriMatcher.match(uri) != SINGLE_FILE) {
+      throw new IllegalArgumentException("Unknown uri id: " + uri);
+    }
+    
+    SQLiteDatabase db = mDbHelper.getWritableDatabase();
+    long rowId = db.insert(ProviderTableMeta.DB_NAME, ProviderTableMeta.FILE_NAME, values);
+    if (rowId > 0) {
+      Uri insertedFileUri = ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_FILE, rowId);
+      getContext().getContentResolver().notifyChange(insertedFileUri, null);
+      return insertedFileUri;
+    }
+    throw new SQLException("ERROR " + uri);
+  }
+
+  @Override
+  public boolean onCreate() {
+    mDbHelper = new DataBaseHelper(getContext());
+    return true;
+  }
+
+  @Override
+  public Cursor query(Uri uri, String[] projection, String selection,
+      String[] selectionArgs, String sortOrder) {
+    SQLiteQueryBuilder sqlQuery = new SQLiteQueryBuilder();
+        
+    sqlQuery.setTables(ProviderTableMeta.DB_NAME);
+    sqlQuery.setProjectionMap(mProjectionMap);
+    
+    switch (mUriMatcher.match(uri)) {
+      case ROOT_DIRECTORY:
+        sqlQuery.appendWhere(ProviderTableMeta.FILE_PARENT + " is null");
+        break;
+      case DIRECTORY:
+        sqlQuery.appendWhere(ProviderTableMeta.FILE_PARENT + "="+uri.getPathSegments().get(1));
+        break;
+      case SINGLE_FILE:
+        if (uri.getPathSegments().size() > 1) {
+          sqlQuery.appendWhere(ProviderTableMeta._ID + "=" +
+                               uri.getPathSegments().get(1));
+        }
+        break;
+      default:
+        throw new IllegalArgumentException("Unknown uri id: " + uri);
+    }
+    
+    String order;
+    if (TextUtils.isEmpty(sortOrder)) {
+      order = ProviderTableMeta.DEFAULT_SORT_ORDER;
+    } else {
+      order = sortOrder;
+    }
+    
+    SQLiteDatabase db = mDbHelper.getReadableDatabase();
+    Cursor c = sqlQuery.query(db, projection, selection, selectionArgs, null, null, order);
+    
+    c.setNotificationUri(getContext().getContentResolver(), uri);
+
+    return c;
+  }
+
+  @Override
+  public int update(Uri uri, ContentValues values, String selection,
+      String[] selectionArgs) {
+    return mDbHelper.getWritableDatabase().update(ProviderTableMeta.DB_NAME, values, selection, selectionArgs);
+  }
+
+  class DataBaseHelper extends SQLiteOpenHelper {
+
+    public DataBaseHelper(Context context) {
+      super(context, ProviderMeta.DB_NAME, null, ProviderMeta.DB_VERSION);
+      
+    }
+    
+    @Override
+    public void onCreate(SQLiteDatabase db) {
+      db.execSQL("CREATE TABLE " + ProviderTableMeta.DB_NAME + "(" +
+                 ProviderTableMeta._ID + " INTEGER PRIMARY KEY, " +
+                 ProviderTableMeta.FILE_NAME + " TEXT, " +
+                 ProviderTableMeta.FILE_PATH + " TEXT, " +
+                 ProviderTableMeta.FILE_PARENT + " INTEGER, " +
+                 ProviderTableMeta.FILE_CREATION + " INTEGER, " +
+                 ProviderTableMeta.FILE_MODIFIED + " INTEGER, " +
+                 ProviderTableMeta.FILE_CONTENT_TYPE + " TEXT, " +
+                 ProviderTableMeta.FILE_CONTENT_LENGTH + " INTEGER, " +
+                 ProviderTableMeta.FILE_STORAGE_PATH + " TEXT, " +
+                 ProviderTableMeta.FILE_ACCOUNT_OWNER + " TEXT);");
+    }
+
+    @Override
+    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+      
+    }
+    
+  }
+  
+}

+ 103 - 79
src/eu/alefzero/owncloud/DbHandler.java → src/eu/alefzero/owncloud/db/DbHandler.java

@@ -1,79 +1,103 @@
-package eu.alefzero.owncloud;
-
-import java.util.Vector;
-
-import android.content.ContentValues;
-import android.content.Context;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteOpenHelper;
-import android.util.Log;
-
-public class DbHandler {
-  private SQLiteDatabase mDB;
-  private OpenerHepler mHelper;
-  private final String mDatabaseName = "ownCloud";
-  private final String TABLE_SESSIONS = "sessions";
-  private final int mDatabaseVersion = 1;
-  
-  public DbHandler(Context context) {
-    mHelper = new OpenerHepler(context);
-    mDB = mHelper.getWritableDatabase();
-  }
-  
-  public Vector<OwnCloudSession> getSessionList() {
-    Cursor c = mDB.query(TABLE_SESSIONS, null, null, null, null, null, null);
-    Vector<OwnCloudSession> v = new Vector<OwnCloudSession>();
-    if (!c.moveToFirst()) {
-      return v;
-    }
-    while (!c.isAfterLast()) {
-      v.add(new OwnCloudSession(c.getString(c.getColumnIndex("sessionName")),
-                                c.getString(c.getColumnIndex("sessionUrl")),
-                                c.getInt(c.getColumnIndex("_id"))));
-      c.moveToNext();
-    }
-    c.close();
-    return v;
-  }
-  
-  public void addSession(String sessionName, String uri) {
-    ContentValues cv = new ContentValues();
-    cv.put("sessionName", sessionName);
-    cv.put("sessionUrl", uri);
-    mDB.insert(TABLE_SESSIONS, null, cv);
-  }
-  
-  public void removeSessionWithId(int sessionId) {
-    mDB.delete(TABLE_SESSIONS, "_id = ?", new String[] {String.valueOf(sessionId)});
-  }
-
-  public void changeSessionFields(int id, String hostname, String uri) {
-    ContentValues cv = new ContentValues();
-    cv.put("sessionName", hostname);
-    cv.put("sessionUrl", uri);
-    mDB.update(TABLE_SESSIONS, cv, "_id = ?", new String[] {String.valueOf(id)});
-  }
-  
-  public void close() {
-    mDB.close();
-  }
-  
-  private class OpenerHepler extends SQLiteOpenHelper {
-    public OpenerHepler(Context context) {
-      super(context, mDatabaseName, null, mDatabaseVersion);
-    }
-
-    @Override
-    public void onCreate(SQLiteDatabase db) {
-      db.execSQL("CREATE TABLE " + TABLE_SESSIONS + " (" +
-                 " _id INTEGER PRIMARY KEY, " +
-                 " sessionName TEXT, " +
-                 " sessionUrl  TEXT);");
-    }
-
-    @Override
-    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
-    }
-  }
-}
+/* ownCloud Android client application
+ *   Copyright (C) 2011  Bartek Przybylski
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package eu.alefzero.owncloud.db;
+
+import java.util.Vector;
+
+import eu.alefzero.owncloud.OwnCloudSession;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.util.Log;
+
+/**
+ * Custom database helper for ownCloud
+ * @author Bartek Przybylski
+ *
+ */
+public class DbHandler {
+  private SQLiteDatabase mDB;
+  private OpenerHepler mHelper;
+  private final String mDatabaseName = "ownCloud";
+  private final String TABLE_SESSIONS = "sessions";
+  private final int mDatabaseVersion = 1;
+  
+  public DbHandler(Context context) {
+    mHelper = new OpenerHepler(context);
+    mDB = mHelper.getWritableDatabase();
+  }
+  
+  public Vector<OwnCloudSession> getSessionList() {
+    Cursor c = mDB.query(TABLE_SESSIONS, null, null, null, null, null, null);
+    Vector<OwnCloudSession> v = new Vector<OwnCloudSession>();
+    if (!c.moveToFirst()) {
+      return v;
+    }
+    while (!c.isAfterLast()) {
+      v.add(new OwnCloudSession(c.getString(c.getColumnIndex("sessionName")),
+                                c.getString(c.getColumnIndex("sessionUrl")),
+                                c.getInt(c.getColumnIndex("_id"))));
+      c.moveToNext();
+    }
+    c.close();
+    return v;
+  }
+  
+  public void addSession(String sessionName, String uri) {
+    ContentValues cv = new ContentValues();
+    cv.put("sessionName", sessionName);
+    cv.put("sessionUrl", uri);
+    mDB.insert(TABLE_SESSIONS, null, cv);
+  }
+  
+  public void removeSessionWithId(int sessionId) {
+    mDB.delete(TABLE_SESSIONS, "_id = ?", new String[] {String.valueOf(sessionId)});
+  }
+
+  public void changeSessionFields(int id, String hostname, String uri) {
+    ContentValues cv = new ContentValues();
+    cv.put("sessionName", hostname);
+    cv.put("sessionUrl", uri);
+    mDB.update(TABLE_SESSIONS, cv, "_id = ?", new String[] {String.valueOf(id)});
+  }
+  
+  public void close() {
+    mDB.close();
+  }
+  
+  private class OpenerHepler extends SQLiteOpenHelper {
+    public OpenerHepler(Context context) {
+      super(context, mDatabaseName, null, mDatabaseVersion);
+    }
+
+    @Override
+    public void onCreate(SQLiteDatabase db) {
+      db.execSQL("CREATE TABLE " + TABLE_SESSIONS + " (" +
+                 " _id INTEGER PRIMARY KEY, " +
+                 " sessionName TEXT, " +
+                 " sessionUrl  TEXT);");
+    }
+
+    @Override
+    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+    }
+  }
+}

+ 64 - 59
src/eu/alefzero/owncloud/db/ProviderMeta.java

@@ -1,59 +1,64 @@
-/* ownCloud Android client application
- *   Copyright (C) 2011  Bartek Przybylski
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation, either version 3 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-package eu.alefzero.owncloud.db;
-
-import android.net.Uri;
-import android.provider.BaseColumns;
-
-public class ProviderMeta {
-
-  public static final String AUTHORITY_FILES = "org.owncloud";
-  public static final String DB_FILE = "owncloud.db";
-  public static final String DB_NAME = "filelist";
-  public static final int DB_VERSION = 1;
-  
-  private ProviderMeta() { }
-  
-  static public class ProviderTableMeta implements BaseColumns {
-    public static final String DB_NAME = "filelist";
-    public static final Uri CONTENT_URI =  
-      Uri.parse("content://" + AUTHORITY_FILES + "/");
-    public static final Uri CONTENT_URI_FILE =
-      Uri.parse("content://" + AUTHORITY_FILES + "/file");
-    public static final Uri CONTENT_URI_DIR =
-      Uri.parse("content://" + AUTHORITY_FILES + "/dir");
-
-    public static final String CONTENT_TYPE =
-      "vnd.android.cursor.dir/vnd.owncloud.file";
-    public static final String CONTENT_TYPE_ITEM =
-      "vnd.android.cursor.item/vnd.owncloud.file";
-    
-    public static final String FILE_PARENT = "parent";
-    public static final String FILE_NAME = "filename";
-    public static final String FILE_CREATION = "created";
-    public static final String FILE_MODIFIED = "modified";
-    public static final String FILE_CONTENT_LENGTH = "content_length";
-    public static final String FILE_CONTENT_TYPE = "content_type";
-    public static final String FILE_STORAGE_PATH = "media_path";
-    public static final String FILE_PATH = "path";
-    public static final String FILE_ACCOUNT_OWNER = "file_owner";
-    
-    public static final String DEFAULT_SORT_ORDER = FILE_NAME + " asc";
-
-  }
-}
+/* ownCloud Android client application
+ *   Copyright (C) 2011  Bartek Przybylski
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package eu.alefzero.owncloud.db;
+
+import android.net.Uri;
+import android.provider.BaseColumns;
+
+/**
+ * Meta-Class that holds various static field information
+ * @author Bartek Przybylski
+ *
+ */
+public class ProviderMeta {
+
+  public static final String AUTHORITY_FILES = "org.owncloud";
+  public static final String DB_FILE = "owncloud.db";
+  public static final String DB_NAME = "filelist";
+  public static final int DB_VERSION = 1;
+  
+  private ProviderMeta() { }
+  
+  static public class ProviderTableMeta implements BaseColumns {
+    public static final String DB_NAME = "filelist";
+    public static final Uri CONTENT_URI =  
+      Uri.parse("content://" + AUTHORITY_FILES + "/");
+    public static final Uri CONTENT_URI_FILE =
+      Uri.parse("content://" + AUTHORITY_FILES + "/file");
+    public static final Uri CONTENT_URI_DIR =
+      Uri.parse("content://" + AUTHORITY_FILES + "/dir");
+
+    public static final String CONTENT_TYPE =
+      "vnd.android.cursor.dir/vnd.owncloud.file";
+    public static final String CONTENT_TYPE_ITEM =
+      "vnd.android.cursor.item/vnd.owncloud.file";
+    
+    public static final String FILE_PARENT = "parent";
+    public static final String FILE_NAME = "filename";
+    public static final String FILE_CREATION = "created";
+    public static final String FILE_MODIFIED = "modified";
+    public static final String FILE_CONTENT_LENGTH = "content_length";
+    public static final String FILE_CONTENT_TYPE = "content_type";
+    public static final String FILE_STORAGE_PATH = "media_path";
+    public static final String FILE_PATH = "path";
+    public static final String FILE_ACCOUNT_OWNER = "file_owner";
+    
+    public static final String DEFAULT_SORT_ORDER = FILE_NAME + " asc";
+
+  }
+}

+ 187 - 170
src/eu/alefzero/owncloud/syncadapter/AbstractOwnCloudSyncAdapter.java

@@ -1,171 +1,188 @@
-package eu.alefzero.owncloud.syncadapter;
-
-import java.io.IOException;
-import java.net.UnknownHostException;
-import java.util.Date;
-import java.util.LinkedList;
-
-import org.apache.http.HttpHost;
-import org.apache.http.HttpRequest;
-import org.apache.http.HttpResponse;
-import org.apache.http.auth.AuthScope;
-import org.apache.http.auth.UsernamePasswordCredentials;
-import org.apache.http.client.ClientProtocolException;
-import org.apache.http.conn.ConnectionKeepAliveStrategy;
-import org.apache.http.impl.auth.BasicScheme;
-import org.apache.http.impl.client.DefaultHttpClient;
-import org.apache.http.protocol.BasicHttpContext;
-import org.apache.http.protocol.HttpContext;
-
-import android.accounts.Account;
-import android.accounts.AccountManager;
-import android.accounts.AuthenticatorException;
-import android.accounts.OperationCanceledException;
-import android.content.AbstractThreadedSyncAdapter;
-import android.content.ContentProviderClient;
-import android.content.Context;
-import android.net.Uri;
-import android.text.TextUtils;
-import eu.alefzero.owncloud.authenticator.AccountAuthenticator;
-import eu.alefzero.webdav.HttpPropFind;
-import eu.alefzero.webdav.TreeNode;
-import eu.alefzero.webdav.TreeNode.NodeProperty;
-import eu.alefzero.webdav.WebdavUtils;
-
-/**
- * Base SyncAdapter for OwnCloud
- * Designed to be subclassed for the concreete SyncAdapter, like ConcatsSync, CalendarSync, FileSync etc..
- * 
- * @author sassman
- *
- */
-public abstract class AbstractOwnCloudSyncAdapter extends AbstractThreadedSyncAdapter {
-
-	private AccountManager accountManager;
-	private Account account;
-	private ContentProviderClient contentProvider;
-	private Date lastUpdated;
-	
-	private DefaultHttpClient client = null;
-	private HttpHost host;
-
-	public AbstractOwnCloudSyncAdapter(Context context, boolean autoInitialize) {
-		super(context, autoInitialize);
-		this.setAccountManager(AccountManager.get(context));
-	}
-
-	public AccountManager getAccountManager() {
-		return accountManager;
-	}
-
-	public void setAccountManager(AccountManager accountManager) {
-		this.accountManager = accountManager;
-	}
-
-	public Account getAccount() {
-		return account;
-	}
-
-	public void setAccount(Account account) {
-		this.account = account;
-	}
-
-	public ContentProviderClient getContentProvider() {
-		return contentProvider;
-	}
-
-	public void setContentProvider(ContentProviderClient contentProvider) {
-		this.contentProvider = contentProvider;
-	}
-
-	public Date getLastUpdated() {
-		return lastUpdated;
-	}
-
-	public void setLastUpdated(Date lastUpdated) {
-		this.lastUpdated = lastUpdated;
-	}
-	
-	protected ConnectionKeepAliveStrategy getKeepAliveStrategy() {
-		return new ConnectionKeepAliveStrategy() {
-			public long getKeepAliveDuration(HttpResponse response, HttpContext context) {
-				// TODO: change keep alive straategy basing on response: ie forbidden/not found/etc
-				// should have keep alive 0
-				// default return: 5s
-				return 5 * 1000;
-			}
-		};
-	}
-	
-	protected HttpPropFind getPropFindQuery() throws OperationCanceledException, AuthenticatorException, IOException {
-		HttpPropFind query = new HttpPropFind(getUri().toString());
-		query.setHeader("Content-type", "text/xml");
-		query.setHeader("User-Agent", "Android-ownCloud");
-		return query;
-	}
-	
-	protected HttpResponse fireRawRequest(HttpRequest query) throws ClientProtocolException, OperationCanceledException, AuthenticatorException, IOException {
-	    BasicHttpContext httpContext = new BasicHttpContext();
-        BasicScheme basicAuth = new BasicScheme();
-        httpContext.setAttribute("preemptive-auth", basicAuth);
-        
-        HttpResponse response = getClient().execute(this.host, query, httpContext);
-        return response;
-	}
-	
-	protected TreeNode fireRequest(HttpRequest query) throws ClientProtocolException, OperationCanceledException, AuthenticatorException, IOException {
-		HttpResponse response = fireRawRequest(query);
-		
-		TreeNode root = new TreeNode();
-		root.setProperty(TreeNode.NodeProperty.NAME, "/");
-		this.parseResponse(response, getUri(), getClient(), this.host, root.getChildList());
-		return root;
-	}
-	
-	protected Uri getUri() {
-		return Uri.parse(this.getAccountManager().getUserData(getAccount(), AccountAuthenticator.KEY_OC_URL));
-	}
-	
-	private DefaultHttpClient getClient() throws OperationCanceledException, AuthenticatorException, IOException {
-		if(this.client == null) {
-			String username = getAccount().name.split("@")[0];
-			String password = this.getAccountManager().blockingGetAuthToken(getAccount(), AccountAuthenticator.AUTH_TOKEN_TYPE, true);
-			if (this.getAccountManager().getUserData(getAccount(), AccountAuthenticator.KEY_OC_URL) == null) {
-				throw new UnknownHostException();
-			}
-			Uri uri = getUri();
-	
-			int port = (uri.getPort() == -1) ? 80 : uri.getPort();
-			this.client = new DefaultHttpClient();
-			this.client.getCredentialsProvider().setCredentials(
-				new AuthScope(uri.getHost(), port),
-				new UsernamePasswordCredentials(username, password)
-			);
-			this.client.setKeepAliveStrategy(this.getKeepAliveStrategy());
-			this.host = new HttpHost(uri.getHost(), port, (uri.getScheme() == "https") ? "https" : "http");
-		}
-		
-		return this.client;
-	}
-	
-	private void parseResponse(HttpResponse resp, Uri uri, DefaultHttpClient client, HttpHost targetHost, LinkedList<TreeNode> insertList) throws IOException, OperationCanceledException, AuthenticatorException {
-		boolean skipFirst = true;
-		for (TreeNode n :WebdavUtils.parseResponseToNodes(resp.getEntity().getContent())) {
-			String path = n.stripPathFromFilename(uri.getPath());
-			if (skipFirst) {
-				skipFirst = false;
-				continue;
-			}
-			insertList.add(n);
-
-			if (!TextUtils.isEmpty(n.getProperty(NodeProperty.NAME)) &&
-					n.getProperty(NodeProperty.RESOURCE_TYPE).equals("DIR")) {
-			    
-			    HttpPropFind method = new HttpPropFind(uri.getPath() + path + n.getProperty(NodeProperty.NAME).replace(" ", "%20") + "/");
-				HttpResponse response = fireRawRequest(method);
-				parseResponse(response, uri, client, targetHost, n.getChildList());
-			}
-		}
-	}
-	
+/* ownCloud Android client application
+ *   Copyright (C) 2011  Bartek Przybylski
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package eu.alefzero.owncloud.syncadapter;
+
+import java.io.IOException;
+import java.net.UnknownHostException;
+import java.util.Date;
+import java.util.LinkedList;
+
+import org.apache.http.HttpHost;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.UsernamePasswordCredentials;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.conn.ConnectionKeepAliveStrategy;
+import org.apache.http.impl.auth.BasicScheme;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.protocol.BasicHttpContext;
+import org.apache.http.protocol.HttpContext;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.accounts.AuthenticatorException;
+import android.accounts.OperationCanceledException;
+import android.content.AbstractThreadedSyncAdapter;
+import android.content.ContentProviderClient;
+import android.content.Context;
+import android.net.Uri;
+import android.text.TextUtils;
+import eu.alefzero.owncloud.authenticator.AccountAuthenticator;
+import eu.alefzero.webdav.HttpPropFind;
+import eu.alefzero.webdav.TreeNode;
+import eu.alefzero.webdav.TreeNode.NodeProperty;
+import eu.alefzero.webdav.WebdavUtils;
+
+/**
+ * Base SyncAdapter for OwnCloud
+ * Designed to be subclassed for the concreete SyncAdapter, like ConcatsSync, CalendarSync, FileSync etc..
+ * 
+ * @author sassman
+ *
+ */
+public abstract class AbstractOwnCloudSyncAdapter extends AbstractThreadedSyncAdapter {
+
+	private AccountManager accountManager;
+	private Account account;
+	private ContentProviderClient contentProvider;
+	private Date lastUpdated;
+	
+	private DefaultHttpClient client = null;
+	private HttpHost host;
+
+	public AbstractOwnCloudSyncAdapter(Context context, boolean autoInitialize) {
+		super(context, autoInitialize);
+		this.setAccountManager(AccountManager.get(context));
+	}
+
+	public AccountManager getAccountManager() {
+		return accountManager;
+	}
+
+	public void setAccountManager(AccountManager accountManager) {
+		this.accountManager = accountManager;
+	}
+
+	public Account getAccount() {
+		return account;
+	}
+
+	public void setAccount(Account account) {
+		this.account = account;
+	}
+
+	public ContentProviderClient getContentProvider() {
+		return contentProvider;
+	}
+
+	public void setContentProvider(ContentProviderClient contentProvider) {
+		this.contentProvider = contentProvider;
+	}
+
+	public Date getLastUpdated() {
+		return lastUpdated;
+	}
+
+	public void setLastUpdated(Date lastUpdated) {
+		this.lastUpdated = lastUpdated;
+	}
+	
+	protected ConnectionKeepAliveStrategy getKeepAliveStrategy() {
+		return new ConnectionKeepAliveStrategy() {
+			public long getKeepAliveDuration(HttpResponse response, HttpContext context) {
+				// TODO: change keep alive straategy basing on response: ie forbidden/not found/etc
+				// should have keep alive 0
+				// default return: 5s
+				return 5 * 1000;
+			}
+		};
+	}
+	
+	protected HttpPropFind getPropFindQuery() throws OperationCanceledException, AuthenticatorException, IOException {
+		HttpPropFind query = new HttpPropFind(getUri().toString());
+		query.setHeader("Content-type", "text/xml");
+		query.setHeader("User-Agent", "Android-ownCloud");
+		return query;
+	}
+	
+	protected HttpResponse fireRawRequest(HttpRequest query) throws ClientProtocolException, OperationCanceledException, AuthenticatorException, IOException {
+	    BasicHttpContext httpContext = new BasicHttpContext();
+        BasicScheme basicAuth = new BasicScheme();
+        httpContext.setAttribute("preemptive-auth", basicAuth);
+        
+        HttpResponse response = getClient().execute(this.host, query, httpContext);
+        return response;
+	}
+	
+	protected TreeNode fireRequest(HttpRequest query) throws ClientProtocolException, OperationCanceledException, AuthenticatorException, IOException {
+		HttpResponse response = fireRawRequest(query);
+		
+		TreeNode root = new TreeNode();
+		root.setProperty(TreeNode.NodeProperty.NAME, "/");
+		this.parseResponse(response, getUri(), getClient(), this.host, root.getChildList());
+		return root;
+	}
+	
+	protected Uri getUri() {
+		return Uri.parse(this.getAccountManager().getUserData(getAccount(), AccountAuthenticator.KEY_OC_URL));
+	}
+	
+	private DefaultHttpClient getClient() throws OperationCanceledException, AuthenticatorException, IOException {
+		if(this.client == null) {
+			String username = getAccount().name.split("@")[0];
+			String password = this.getAccountManager().blockingGetAuthToken(getAccount(), AccountAuthenticator.AUTH_TOKEN_TYPE, true);
+			if (this.getAccountManager().getUserData(getAccount(), AccountAuthenticator.KEY_OC_URL) == null) {
+				throw new UnknownHostException();
+			}
+			Uri uri = getUri();
+	
+			int port = (uri.getPort() == -1) ? 80 : uri.getPort();
+			this.client = new DefaultHttpClient();
+			this.client.getCredentialsProvider().setCredentials(
+				new AuthScope(uri.getHost(), port),
+				new UsernamePasswordCredentials(username, password)
+			);
+			this.client.setKeepAliveStrategy(this.getKeepAliveStrategy());
+			this.host = new HttpHost(uri.getHost(), port, (uri.getScheme() == "https") ? "https" : "http");
+		}
+		
+		return this.client;
+	}
+	
+	private void parseResponse(HttpResponse resp, Uri uri, DefaultHttpClient client, HttpHost targetHost, LinkedList<TreeNode> insertList) throws IOException, OperationCanceledException, AuthenticatorException {
+		boolean skipFirst = true;
+		for (TreeNode n :WebdavUtils.parseResponseToNodes(resp.getEntity().getContent())) {
+			String path = n.stripPathFromFilename(uri.getPath());
+			if (skipFirst) {
+				skipFirst = false;
+				continue;
+			}
+			insertList.add(n);
+
+			if (!TextUtils.isEmpty(n.getProperty(NodeProperty.NAME)) &&
+					n.getProperty(NodeProperty.RESOURCE_TYPE).equals("DIR")) {
+			    
+			    HttpPropFind method = new HttpPropFind(uri.getPath() + path + n.getProperty(NodeProperty.NAME).replace(" ", "%20") + "/");
+				HttpResponse response = fireRawRequest(method);
+				parseResponse(response, uri, client, targetHost, n.getChildList());
+			}
+		}
+	}
+	
 }

+ 142 - 140
src/eu/alefzero/owncloud/syncadapter/FileSyncAdapter.java

@@ -1,140 +1,142 @@
-/* ownCloud Android client application
- *   Copyright (C) 2011  Bartek Przybylski
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation, either version 3 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-package eu.alefzero.owncloud.syncadapter;
-
-import java.io.IOException;
-
-import org.apache.http.entity.StringEntity;
-
-import android.accounts.Account;
-import android.accounts.AuthenticatorException;
-import android.accounts.OperationCanceledException;
-import android.content.ContentProviderClient;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.SyncResult;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.util.Log;
-import eu.alefzero.owncloud.db.ProviderMeta.ProviderTableMeta;
-import eu.alefzero.webdav.HttpPropFind;
-import eu.alefzero.webdav.TreeNode;
-import eu.alefzero.webdav.TreeNode.NodeProperty;
-import eu.alefzero.webdav.WebdavUtils;
-
-/**
- * SyncAdapter implementation for syncing sample SyncAdapter contacts to the
- * platform ContactOperations provider.
- */
-public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
-	private static final String TAG = "FileSyncAdapter";
-
-	public FileSyncAdapter(Context context, boolean autoInitialize) {
-		super(context, autoInitialize);
-	}
-
-	@Override
-	public synchronized void onPerformSync(
-			Account account, 
-			Bundle extras, 
-			String authority, 
-			ContentProviderClient provider, 
-			SyncResult syncResult) {
-
-		try {
-			this.setAccount(account);
-			this.setContentProvider(provider);
-
-			HttpPropFind query = this.getPropFindQuery();
-			query.setEntity(new StringEntity(WebdavUtils.prepareXmlForPropFind()));
-			TreeNode root = this.fireRequest(query);
-
-			commitToDatabase(root, null);
-		} catch (OperationCanceledException e) {
-			e.printStackTrace();
-		} catch (AuthenticatorException e) {
-			syncResult.stats.numAuthExceptions++;
-			e.printStackTrace();
-		} catch (IOException e) {
-			syncResult.stats.numIoExceptions++;
-			e.printStackTrace();
-		} catch (RemoteException e) {
-			e.printStackTrace();
-		}
-	}
-
-	private void commitToDatabase(TreeNode root, String parentId) throws RemoteException {
-		for (TreeNode n : root.getChildList()) {
-			Log.d(TAG, n.toString());
-			ContentValues cv = new ContentValues();
-			cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, n.getProperty(NodeProperty.CONTENT_LENGTH));
-			cv.put(ProviderTableMeta.FILE_MODIFIED, n.getProperty(NodeProperty.LAST_MODIFIED_DATE));
-			cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, n.getProperty(NodeProperty.RESOURCE_TYPE));
-			cv.put(ProviderTableMeta.FILE_PARENT, parentId);
-
-			String name = n.getProperty(NodeProperty.NAME),
-					path = n.getProperty(NodeProperty.PATH);
-			Cursor c = this.getContentProvider().query(ProviderTableMeta.CONTENT_URI_FILE,
-					null,
-					ProviderTableMeta.FILE_NAME+"=? AND " + ProviderTableMeta.FILE_PATH + "=? AND " + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?",
-					new String[]{name, path, this.getAccount().name},
-					null);
-			if (c.moveToFirst()) {
-				this.getContentProvider().update(ProviderTableMeta.CONTENT_URI,
-						cv,
-						ProviderTableMeta._ID+"=?",
-								new String[]{c.getString(c.getColumnIndex(ProviderTableMeta._ID))});
-				Log.d(TAG, "ID of: "+name+":"+c.getString(c.getColumnIndex(ProviderTableMeta._ID)));
-			} else {
-				cv.put(ProviderTableMeta.FILE_NAME, n.getProperty(NodeProperty.NAME));
-				cv.put(ProviderTableMeta.FILE_PATH, n.getProperty(NodeProperty.PATH));
-				cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, this.getAccount().name);
-				Uri entry = this.getContentProvider().insert(ProviderTableMeta.CONTENT_URI_FILE, cv);
-				Log.d(TAG, "Inserting new entry " + path + name);
-				c = this.getContentProvider().query(entry, null, null, null, null);
-				c.moveToFirst();
-			}
-			if (n.getProperty(NodeProperty.RESOURCE_TYPE).equals("DIR")) {
-				commitToDatabase(n, c.getString(c.getColumnIndex(ProviderTableMeta._ID)));
-			}
-		}
-		// clean removed files
-		String[] selection = new String[root.getChildList().size()+2];
-		selection[0] = this.getAccount().name;
-		selection[1] = parentId;
-		String qm = "";
-		for (int i = 2; i < selection.length-1; ++i) {
-			qm += "?,";
-			selection[i] = root.getChildList().get(i-2).getProperty(NodeProperty.NAME);
-		}
-		if (selection.length >= 3) {
-			selection[selection.length-1] = root.getChildrenNames()[selection.length-3];
-			qm += "?";
-		}
-		for (int i = 0; i < selection.length; ++i) {
-			Log.d(TAG,selection[i]+"");
-		}
-		Log.d(TAG,"Removing files "+ parentId);
-		this.getContentProvider().delete(ProviderTableMeta.CONTENT_URI,
-				ProviderTableMeta.FILE_ACCOUNT_OWNER+"=? AND " + ProviderTableMeta.FILE_PARENT + (parentId==null?" IS ":"=")+"? AND " + ProviderTableMeta.FILE_NAME + " NOT IN ("+qm+")",
-				selection);
-	}
-}
+/* ownCloud Android client application
+ *   Copyright (C) 2011  Bartek Przybylski
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package eu.alefzero.owncloud.syncadapter;
+
+import java.io.IOException;
+
+import org.apache.http.entity.StringEntity;
+
+import android.accounts.Account;
+import android.accounts.AuthenticatorException;
+import android.accounts.OperationCanceledException;
+import android.content.ContentProviderClient;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.SyncResult;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.util.Log;
+import eu.alefzero.owncloud.db.ProviderMeta.ProviderTableMeta;
+import eu.alefzero.webdav.HttpPropFind;
+import eu.alefzero.webdav.TreeNode;
+import eu.alefzero.webdav.TreeNode.NodeProperty;
+import eu.alefzero.webdav.WebdavUtils;
+
+/**
+ * SyncAdapter implementation for syncing sample SyncAdapter contacts to the
+ * platform ContactOperations provider.
+ * 
+ * @author Bartek Przybylski
+ */
+public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
+	private static final String TAG = "FileSyncAdapter";
+
+	public FileSyncAdapter(Context context, boolean autoInitialize) {
+		super(context, autoInitialize);
+	}
+
+	@Override
+	public synchronized void onPerformSync(
+			Account account, 
+			Bundle extras, 
+			String authority, 
+			ContentProviderClient provider, 
+			SyncResult syncResult) {
+
+		try {
+			this.setAccount(account);
+			this.setContentProvider(provider);
+
+			HttpPropFind query = this.getPropFindQuery();
+			query.setEntity(new StringEntity(WebdavUtils.prepareXmlForPropFind()));
+			TreeNode root = this.fireRequest(query);
+
+			commitToDatabase(root, null);
+		} catch (OperationCanceledException e) {
+			e.printStackTrace();
+		} catch (AuthenticatorException e) {
+			syncResult.stats.numAuthExceptions++;
+			e.printStackTrace();
+		} catch (IOException e) {
+			syncResult.stats.numIoExceptions++;
+			e.printStackTrace();
+		} catch (RemoteException e) {
+			e.printStackTrace();
+		}
+	}
+
+	private void commitToDatabase(TreeNode root, String parentId) throws RemoteException {
+		for (TreeNode n : root.getChildList()) {
+			Log.d(TAG, n.toString());
+			ContentValues cv = new ContentValues();
+			cv.put(ProviderTableMeta.FILE_CONTENT_LENGTH, n.getProperty(NodeProperty.CONTENT_LENGTH));
+			cv.put(ProviderTableMeta.FILE_MODIFIED, n.getProperty(NodeProperty.LAST_MODIFIED_DATE));
+			cv.put(ProviderTableMeta.FILE_CONTENT_TYPE, n.getProperty(NodeProperty.RESOURCE_TYPE));
+			cv.put(ProviderTableMeta.FILE_PARENT, parentId);
+
+			String name = n.getProperty(NodeProperty.NAME),
+					path = n.getProperty(NodeProperty.PATH);
+			Cursor c = this.getContentProvider().query(ProviderTableMeta.CONTENT_URI_FILE,
+					null,
+					ProviderTableMeta.FILE_NAME+"=? AND " + ProviderTableMeta.FILE_PATH + "=? AND " + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?",
+					new String[]{name, path, this.getAccount().name},
+					null);
+			if (c.moveToFirst()) {
+				this.getContentProvider().update(ProviderTableMeta.CONTENT_URI,
+						cv,
+						ProviderTableMeta._ID+"=?",
+								new String[]{c.getString(c.getColumnIndex(ProviderTableMeta._ID))});
+				Log.d(TAG, "ID of: "+name+":"+c.getString(c.getColumnIndex(ProviderTableMeta._ID)));
+			} else {
+				cv.put(ProviderTableMeta.FILE_NAME, n.getProperty(NodeProperty.NAME));
+				cv.put(ProviderTableMeta.FILE_PATH, n.getProperty(NodeProperty.PATH));
+				cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, this.getAccount().name);
+				Uri entry = this.getContentProvider().insert(ProviderTableMeta.CONTENT_URI_FILE, cv);
+				Log.d(TAG, "Inserting new entry " + path + name);
+				c = this.getContentProvider().query(entry, null, null, null, null);
+				c.moveToFirst();
+			}
+			if (n.getProperty(NodeProperty.RESOURCE_TYPE).equals("DIR")) {
+				commitToDatabase(n, c.getString(c.getColumnIndex(ProviderTableMeta._ID)));
+			}
+		}
+		// clean removed files
+		String[] selection = new String[root.getChildList().size()+2];
+		selection[0] = this.getAccount().name;
+		selection[1] = parentId;
+		String qm = "";
+		for (int i = 2; i < selection.length-1; ++i) {
+			qm += "?,";
+			selection[i] = root.getChildList().get(i-2).getProperty(NodeProperty.NAME);
+		}
+		if (selection.length >= 3) {
+			selection[selection.length-1] = root.getChildrenNames()[selection.length-3];
+			qm += "?";
+		}
+		for (int i = 0; i < selection.length; ++i) {
+			Log.d(TAG,selection[i]+"");
+		}
+		Log.d(TAG,"Removing files "+ parentId);
+		this.getContentProvider().delete(ProviderTableMeta.CONTENT_URI,
+				ProviderTableMeta.FILE_ACCOUNT_OWNER+"=? AND " + ProviderTableMeta.FILE_PARENT + (parentId==null?" IS ":"=")+"? AND " + ProviderTableMeta.FILE_NAME + " NOT IN ("+qm+")",
+				selection);
+	}
+}

+ 53 - 31
src/eu/alefzero/owncloud/syncadapter/FileSyncService.java

@@ -1,31 +1,53 @@
-
-package eu.alefzero.owncloud.syncadapter;
-
-import android.app.Service;
-import android.content.Intent;
-import android.os.IBinder;
-
-public class FileSyncService extends Service {
-    private static final Object syncAdapterLock = new Object();
-    private static AbstractOwnCloudSyncAdapter concretSyncAdapter = null;
-
-    /*
-     * {@inheritDoc}
-     */
-    @Override
-    public void onCreate() {
-        synchronized (syncAdapterLock) {
-            if (concretSyncAdapter == null) {
-                concretSyncAdapter = new FileSyncAdapter(getApplicationContext(), true);
-            }
-        }
-    }
-
-    /*
-     * {@inheritDoc}
-     */
-    @Override
-    public IBinder onBind(Intent intent) {
-        return concretSyncAdapter.getSyncAdapterBinder();
-    }
-}
+/* ownCloud Android client application
+ *   Copyright (C) 2011  Bartek Przybylski
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package eu.alefzero.owncloud.syncadapter;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+/**
+ * Background service for syncing files to our
+ * local Database
+ * @author Bartek Przybylski
+ *
+ */
+public class FileSyncService extends Service {
+    private static final Object syncAdapterLock = new Object();
+    private static AbstractOwnCloudSyncAdapter concretSyncAdapter = null;
+
+    /*
+     * {@inheritDoc}
+     */
+    @Override
+    public void onCreate() {
+        synchronized (syncAdapterLock) {
+            if (concretSyncAdapter == null) {
+                concretSyncAdapter = new FileSyncAdapter(getApplicationContext(), true);
+            }
+        }
+    }
+
+    /*
+     * {@inheritDoc}
+     */
+    @Override
+    public IBinder onBind(Intent intent) {
+        return concretSyncAdapter.getSyncAdapterBinder();
+    }
+}

+ 59 - 0
src/eu/alefzero/owncloud/ui/ActionItem.java

@@ -0,0 +1,59 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2011  Bartek Przybylski
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package eu.alefzero.owncloud.ui;
+
+import android.graphics.drawable.Drawable;
+import android.view.View.OnClickListener;
+
+/**
+* Represents an Item on the ActionBar.
+* @author Bartek Przybylski
+* 
+*/
+public class ActionItem {
+  private Drawable mIcon;
+  private String mTitle;
+  private OnClickListener mClickListener;
+  
+  public ActionItem() { }
+  
+  public void setTitle(String title) {
+    mTitle = title;
+  }
+  
+  public String getTitle() {
+    return mTitle;
+  }
+  
+  public void setIcon(Drawable icon) {
+    mIcon = icon;
+  }
+  
+  public Drawable getIcon() {
+    return mIcon;
+  }
+  
+  public void setOnClickListener(OnClickListener listener) {
+    mClickListener = listener;
+  }
+  
+  public OnClickListener getOnClickListerner() {
+    return mClickListener;
+  }
+  
+}

+ 148 - 126
src/eu/alefzero/owncloud/CustomPopup.java → src/eu/alefzero/owncloud/ui/CustomPopup.java

@@ -1,126 +1,148 @@
-package eu.alefzero.owncloud;
-
-import android.content.Context;
-import android.graphics.Rect;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.view.Gravity;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.WindowManager;
-import android.view.View.OnTouchListener;
-import android.view.ViewGroup.LayoutParams;
-import android.widget.PopupWindow;
-
-public class CustomPopup {
-  protected final View mAnchor;
-  protected final PopupWindow mWindow;
-  private View root;
-  private Drawable background = null;
-  protected final WindowManager mWManager;
-  
-  public CustomPopup(View anchor) {
-    mAnchor = anchor;
-    mWindow = new PopupWindow(anchor.getContext());
-    
-    mWindow.setTouchInterceptor(new OnTouchListener() {
-      
-      public boolean onTouch(View v, MotionEvent event) {
-        if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
-          CustomPopup.this.dismiss();
-          return true;
-        }
-        return false;
-      }
-    });
-    
-    mWManager = (WindowManager) anchor.getContext().getSystemService(Context.WINDOW_SERVICE);
-    onCreate();
-  }
-  
-  
-  public void onCreate() {}
-  public void onShow() {}
-  
-  public void preShow() {
-    if (root == null) {
-      throw new IllegalStateException("setContentView called with a view to display");
-    }
-    
-    onShow();
-    
-    if (background == null) {
-      mWindow.setBackgroundDrawable(new BitmapDrawable());
-    } else {
-      mWindow.setBackgroundDrawable(background);
-    }
-    
-    mWindow.setWidth(WindowManager.LayoutParams.WRAP_CONTENT);
-    mWindow.setHeight(WindowManager.LayoutParams.WRAP_CONTENT);
-    mWindow.setTouchable(true);
-    mWindow.setFocusable(true);
-    mWindow.setOutsideTouchable(true);
-    
-    mWindow.setContentView(root);
-  }
-  
-  public void setBackgroundDrawable(Drawable background) {
-    this.background = background;
-  }
-  
-  public void setContentView(View root) {
-    this.root = root;
-    mWindow.setContentView(root);
-  }
-  
-  public void setContentView(int layoutResId) {
-    LayoutInflater inflater = 
-      (LayoutInflater) mAnchor.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-    setContentView(inflater.inflate(layoutResId, null));
-  }
-  
-  public void showDropDown() {
-    showDropDown(0, 0);
-  }
-  
-  public void showDropDown(int x, int y) {
-    preShow();
-    mWindow.setAnimationStyle(android.R.style.Animation_Dialog);
-    mWindow.showAsDropDown(mAnchor, x, y);
-  }
-  
-  public void showLikeQuickAction() {
-    showLikeQuickAction(0, 0);
-  }
-  
-  public void showLikeQuickAction(int x, int y) {
-    preShow();
-    
-    mWindow.setAnimationStyle(android.R.style.Animation_Dialog);
-    int[] location = new int[2];
-    mAnchor.getLocationOnScreen(location);
-    
-    Rect anchorRect = 
-      new Rect(location[0], location[1], location[0] + mAnchor.getWidth(), location[1] + mAnchor.getHeight());
-    
-    root.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
-    root.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
-    
-    int rootW = root.getWidth(), rootH = root.getHeight();
-    int screenW = mWManager.getDefaultDisplay().getWidth();
-    
-    int xpos = ((screenW-rootW)/2) + x;
-    int ypos = anchorRect.top - rootH + y;
-    
-    if (rootH > anchorRect.top) {
-      ypos = anchorRect.bottom + y;
-    }
-    mWindow.showAtLocation(mAnchor, Gravity.NO_GRAVITY, xpos, ypos);
-  }
-  
-  public void dismiss() {
-    mWindow.dismiss();
-  }
-  
-}
+/* ownCloud Android client application
+ *   Copyright (C) 2011  Bartek Przybylski
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package eu.alefzero.owncloud.ui;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.View.OnTouchListener;
+import android.view.ViewGroup.LayoutParams;
+import android.widget.PopupWindow;
+
+/**
+ * Represents a custom PopupWindows
+ * @author Lorensius. W. T
+ *
+ */
+public class CustomPopup {
+  protected final View mAnchor;
+  protected final PopupWindow mWindow;
+  private View root;
+  private Drawable background = null;
+  protected final WindowManager mWManager;
+  
+  public CustomPopup(View anchor) {
+    mAnchor = anchor;
+    mWindow = new PopupWindow(anchor.getContext());
+    
+    mWindow.setTouchInterceptor(new OnTouchListener() {
+      
+      public boolean onTouch(View v, MotionEvent event) {
+        if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
+          CustomPopup.this.dismiss();
+          return true;
+        }
+        return false;
+      }
+    });
+    
+    mWManager = (WindowManager) anchor.getContext().getSystemService(Context.WINDOW_SERVICE);
+    onCreate();
+  }
+  
+  
+  public void onCreate() {}
+  public void onShow() {}
+  
+  public void preShow() {
+    if (root == null) {
+      throw new IllegalStateException("setContentView called with a view to display");
+    }
+    
+    onShow();
+    
+    if (background == null) {
+      mWindow.setBackgroundDrawable(new BitmapDrawable());
+    } else {
+      mWindow.setBackgroundDrawable(background);
+    }
+    
+    mWindow.setWidth(WindowManager.LayoutParams.WRAP_CONTENT);
+    mWindow.setHeight(WindowManager.LayoutParams.WRAP_CONTENT);
+    mWindow.setTouchable(true);
+    mWindow.setFocusable(true);
+    mWindow.setOutsideTouchable(true);
+    
+    mWindow.setContentView(root);
+  }
+  
+  public void setBackgroundDrawable(Drawable background) {
+    this.background = background;
+  }
+  
+  public void setContentView(View root) {
+    this.root = root;
+    mWindow.setContentView(root);
+  }
+  
+  public void setContentView(int layoutResId) {
+    LayoutInflater inflater = 
+      (LayoutInflater) mAnchor.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+    setContentView(inflater.inflate(layoutResId, null));
+  }
+  
+  public void showDropDown() {
+    showDropDown(0, 0);
+  }
+  
+  public void showDropDown(int x, int y) {
+    preShow();
+    mWindow.setAnimationStyle(android.R.style.Animation_Dialog);
+    mWindow.showAsDropDown(mAnchor, x, y);
+  }
+  
+  public void showLikeQuickAction() {
+    showLikeQuickAction(0, 0);
+  }
+  
+  public void showLikeQuickAction(int x, int y) {
+    preShow();
+    
+    mWindow.setAnimationStyle(android.R.style.Animation_Dialog);
+    int[] location = new int[2];
+    mAnchor.getLocationOnScreen(location);
+    
+    Rect anchorRect = 
+      new Rect(location[0], location[1], location[0] + mAnchor.getWidth(), location[1] + mAnchor.getHeight());
+    
+    root.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
+    root.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+    
+    int rootW = root.getWidth(), rootH = root.getHeight();
+    int screenW = mWManager.getDefaultDisplay().getWidth();
+    
+    int xpos = ((screenW-rootW)/2) + x;
+    int ypos = anchorRect.top - rootH + y;
+    
+    if (rootH > anchorRect.top) {
+      ypos = anchorRect.bottom + y;
+    }
+    mWindow.showAtLocation(mAnchor, Gravity.NO_GRAVITY, xpos, ypos);
+  }
+  
+  public void dismiss() {
+    mWindow.dismiss();
+  }
+  
+}

+ 23 - 1
src/eu/alefzero/owncloud/QuickAction.java → src/eu/alefzero/owncloud/ui/QuickAction.java

@@ -1,4 +1,21 @@
-package eu.alefzero.owncloud;
+/* ownCloud Android client application
+ *   Copyright (C) 2011  Bartek Przybylski
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package eu.alefzero.owncloud.ui;
 
 import android.content.Context;
 
@@ -19,6 +36,11 @@ import android.view.ViewGroup;
 
 import java.util.ArrayList;
 
+import eu.alefzero.owncloud.R;
+import eu.alefzero.owncloud.R.id;
+import eu.alefzero.owncloud.R.layout;
+import eu.alefzero.owncloud.R.style;
+
 /**
  * Popup window, shows action list as icon and text like the one in Gallery3D app. 
  * 

+ 191 - 186
src/eu/alefzero/owncloud/ui/AuthenticatorActivity.java → src/eu/alefzero/owncloud/ui/activity/AuthenticatorActivity.java

@@ -1,186 +1,191 @@
-/* ownCloud Android client application
- *   Copyright (C) 2011  Bartek Przybylski
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation, either version 3 of the License, or
- *   (at your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-package eu.alefzero.owncloud.ui;
-
-import java.net.MalformedURLException;
-import java.net.URL;
-
-import android.accounts.Account;
-import android.accounts.AccountAuthenticatorActivity;
-import android.accounts.AccountManager;
-import android.app.Dialog;
-import android.app.ProgressDialog;
-import android.content.ContentResolver;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.graphics.Color;
-import android.os.Bundle;
-import android.os.Handler;
-import android.util.Log;
-import android.view.View;
-import android.view.Window;
-import android.widget.TextView;
-import android.widget.Toast;
-import eu.alefzero.owncloud.R;
-import eu.alefzero.owncloud.authenticator.AccountAuthenticator;
-import eu.alefzero.owncloud.authenticator.AuthUtils;
-import eu.alefzero.owncloud.db.ProviderMeta.ProviderTableMeta;
-
-public class AuthenticatorActivity extends AccountAuthenticatorActivity {
-    private Thread mAuthThread;
-    private final Handler mHandler = new Handler();
-
-    public static final String PARAM_USERNAME = "param_Username";
-    public static final String PARAM_HOSTNAME = "param_Hostname";
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        getWindow().requestFeature(Window.FEATURE_NO_TITLE);
-        setContentView(R.layout.account_setup);
-        if (getIntent().hasExtra(PARAM_USERNAME)) {
-            String username = getIntent().getStringExtra(PARAM_HOSTNAME);
-            TextView host_text, user_text;
-            host_text = (TextView) findViewById(R.id.host_URL);
-            user_text = (TextView) findViewById(R.id.account_username);
-            host_text.setText(host_text.getText() + username.substring(username.lastIndexOf('@')));
-            user_text.setText(user_text.getText() + username.substring(0, username.lastIndexOf('@') - 1));
-        }
-    }
-
-    @Override
-    protected Dialog onCreateDialog(int id) {
-        final ProgressDialog dialog = new ProgressDialog(this);
-        dialog.setMessage("Trying to login");
-        dialog.setIndeterminate(true);
-        dialog.setCancelable(true);
-        dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
-            public void onCancel(DialogInterface dialog) {
-                Log.i(getClass().getName(), "Login canceled");
-                if (mAuthThread != null) {
-                    mAuthThread.interrupt();
-                    finish();
-                }
-            }
-        });
-        return dialog;
-    }
-
-    public void onAuthenticationResult(boolean result, String message) {
-        if (result) {
-            TextView username_text = (TextView) findViewById(R.id.account_username),
-                    password_text = (TextView) findViewById(R.id.account_password);
-
-            URL url;
-            try {
-                url = new URL(message);
-            } catch (MalformedURLException e) {
-                // should never happend
-                Log.e(getClass().getName(), "Malformed URL: " + message);
-                return;
-            }
-
-            String username = username_text.getText().toString().trim();
-            Account account = new Account(username + "@" + url.getHost(), AccountAuthenticator.ACCOUNT_TYPE);
-            AccountManager accManager = AccountManager.get(this);
-            accManager.addAccountExplicitly(account, password_text.getText().toString(), null);
-
-            final Intent intent = new Intent();
-            intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE, AccountAuthenticator.ACCOUNT_TYPE);
-            intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, account.name);
-            intent.putExtra(AccountManager.KEY_AUTHTOKEN, AccountAuthenticator.ACCOUNT_TYPE);
-            accManager.setUserData(account, AccountAuthenticator.KEY_OC_URL, url.toString());
-
-            // TODO prepare this URL during a central service
-            intent.putExtra(AccountManager.KEY_USERDATA, username);
-            accManager.setUserData(account, AccountAuthenticator.KEY_CONTACT_URL,
-                    url.toString().replace(AuthUtils.WEBDAV_PATH_2_0, AuthUtils.CARDDAV_PATH_2_0)
-            );
-
-            setAccountAuthenticatorResult(intent.getExtras());
-            setResult(RESULT_OK, intent);
-            Bundle bundle = new Bundle();
-            bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
-            getContentResolver().startSync(ProviderTableMeta.CONTENT_URI, bundle);
-
-            dismissDialog(0);
-            finish();
-        } else {
-            Toast.makeText(this, message, Toast.LENGTH_LONG).show();
-            dismissDialog(0);
-        }
-    }
-
-    public void onCancelClick(View view) {
-        Log.i(getClass().getName(), "Account creating canceled");
-        this.finish();
-    }
-
-    public void onOkClick(View view) {
-        TextView url_text = (TextView) findViewById(R.id.host_URL);
-        TextView username_text = (TextView) findViewById(R.id.account_username);
-        TextView password_text = (TextView) findViewById(R.id.account_password);
-        Log.i(getClass().getName(), "OK clicked");
-        boolean hasErrors = false;
-
-        URL uri = null;
-        if (url_text.getText().toString().trim().length() == 0) {
-            url_text.setTextColor(Color.RED);
-            hasErrors = true;
-        } else {
-            url_text.setTextColor(Color.BLACK);
-        }
-        try {
-            String url_str = url_text.getText().toString();
-            if (!url_str.startsWith("http://") &&
-                    !url_str.startsWith("https://")) {
-                url_str = "http://" + url_str;
-            }
-            uri = new URL(url_str);
-        } catch (MalformedURLException e) {
-            url_text.setTextColor(Color.RED);
-            e.printStackTrace();
-            hasErrors = true;
-        }
-
-        if (username_text.getText().toString().contains(" ") ||
-                username_text.getText().toString().trim().length() == 0) {
-            username_text.setTextColor(Color.RED);
-            hasErrors = true;
-        } else {
-            username_text.setTextColor(Color.BLACK);
-        }
-
-        if (password_text.getText().toString().trim().length() == 0) {
-            password_text.setTextColor(Color.RED);
-            hasErrors = true;
-        } else {
-            password_text.setTextColor(Color.BLACK);
-        }
-        if (hasErrors) {
-            return;
-        }
-        showDialog(0);
-        mAuthThread = AuthUtils.attemptAuth(uri,
-                username_text.getText().toString(),
-                password_text.getText().toString(),
-                mHandler,
-                AuthenticatorActivity.this);
-    }
-}
+/* ownCloud Android client application
+ *   Copyright (C) 2011  Bartek Przybylski
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package eu.alefzero.owncloud.ui.activity;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import android.accounts.Account;
+import android.accounts.AccountAuthenticatorActivity;
+import android.accounts.AccountManager;
+import android.app.Dialog;
+import android.app.ProgressDialog;
+import android.content.ContentResolver;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.os.Handler;
+import android.util.Log;
+import android.view.View;
+import android.view.Window;
+import android.widget.TextView;
+import android.widget.Toast;
+import eu.alefzero.owncloud.R;
+import eu.alefzero.owncloud.authenticator.AccountAuthenticator;
+import eu.alefzero.owncloud.authenticator.AuthUtils;
+import eu.alefzero.owncloud.db.ProviderMeta.ProviderTableMeta;
+
+/**
+ * This Activity is used to add an ownCloud account to the App
+ * @author Bartek Przybylski
+ *
+ */
+public class AuthenticatorActivity extends AccountAuthenticatorActivity {
+    private Thread mAuthThread;
+    private final Handler mHandler = new Handler();
+
+    public static final String PARAM_USERNAME = "param_Username";
+    public static final String PARAM_HOSTNAME = "param_Hostname";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        getWindow().requestFeature(Window.FEATURE_NO_TITLE);
+        setContentView(R.layout.account_setup);
+        if (getIntent().hasExtra(PARAM_USERNAME)) {
+            String username = getIntent().getStringExtra(PARAM_HOSTNAME);
+            TextView host_text, user_text;
+            host_text = (TextView) findViewById(R.id.host_URL);
+            user_text = (TextView) findViewById(R.id.account_username);
+            host_text.setText(host_text.getText() + username.substring(username.lastIndexOf('@')));
+            user_text.setText(user_text.getText() + username.substring(0, username.lastIndexOf('@') - 1));
+        }
+    }
+
+    @Override
+    protected Dialog onCreateDialog(int id) {
+        final ProgressDialog dialog = new ProgressDialog(this);
+        dialog.setMessage("Trying to login");
+        dialog.setIndeterminate(true);
+        dialog.setCancelable(true);
+        dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
+            public void onCancel(DialogInterface dialog) {
+                Log.i(getClass().getName(), "Login canceled");
+                if (mAuthThread != null) {
+                    mAuthThread.interrupt();
+                    finish();
+                }
+            }
+        });
+        return dialog;
+    }
+
+    public void onAuthenticationResult(boolean result, String message) {
+        if (result) {
+            TextView username_text = (TextView) findViewById(R.id.account_username),
+                    password_text = (TextView) findViewById(R.id.account_password);
+
+            URL url;
+            try {
+                url = new URL(message);
+            } catch (MalformedURLException e) {
+                // should never happend
+                Log.e(getClass().getName(), "Malformed URL: " + message);
+                return;
+            }
+
+            String username = username_text.getText().toString().trim();
+            Account account = new Account(username + "@" + url.getHost(), AccountAuthenticator.ACCOUNT_TYPE);
+            AccountManager accManager = AccountManager.get(this);
+            accManager.addAccountExplicitly(account, password_text.getText().toString(), null);
+
+            final Intent intent = new Intent();
+            intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE, AccountAuthenticator.ACCOUNT_TYPE);
+            intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, account.name);
+            intent.putExtra(AccountManager.KEY_AUTHTOKEN, AccountAuthenticator.ACCOUNT_TYPE);
+            accManager.setUserData(account, AccountAuthenticator.KEY_OC_URL, url.toString());
+
+            // TODO prepare this URL during a central service
+            intent.putExtra(AccountManager.KEY_USERDATA, username);
+            accManager.setUserData(account, AccountAuthenticator.KEY_CONTACT_URL,
+                    url.toString().replace(AuthUtils.WEBDAV_PATH_2_0, AuthUtils.CARDDAV_PATH_2_0)
+            );
+
+            setAccountAuthenticatorResult(intent.getExtras());
+            setResult(RESULT_OK, intent);
+            Bundle bundle = new Bundle();
+            bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
+            getContentResolver().startSync(ProviderTableMeta.CONTENT_URI, bundle);
+
+            dismissDialog(0);
+            finish();
+        } else {
+            Toast.makeText(this, message, Toast.LENGTH_LONG).show();
+            dismissDialog(0);
+        }
+    }
+
+    public void onCancelClick(View view) {
+        Log.i(getClass().getName(), "Account creating canceled");
+        this.finish();
+    }
+
+    public void onOkClick(View view) {
+        TextView url_text = (TextView) findViewById(R.id.host_URL);
+        TextView username_text = (TextView) findViewById(R.id.account_username);
+        TextView password_text = (TextView) findViewById(R.id.account_password);
+        Log.i(getClass().getName(), "OK clicked");
+        boolean hasErrors = false;
+
+        URL uri = null;
+        if (url_text.getText().toString().trim().length() == 0) {
+            url_text.setTextColor(Color.RED);
+            hasErrors = true;
+        } else {
+            url_text.setTextColor(Color.BLACK);
+        }
+        try {
+            String url_str = url_text.getText().toString();
+            if (!url_str.startsWith("http://") &&
+                    !url_str.startsWith("https://")) {
+                url_str = "http://" + url_str;
+            }
+            uri = new URL(url_str);
+        } catch (MalformedURLException e) {
+            url_text.setTextColor(Color.RED);
+            e.printStackTrace();
+            hasErrors = true;
+        }
+
+        if (username_text.getText().toString().contains(" ") ||
+                username_text.getText().toString().trim().length() == 0) {
+            username_text.setTextColor(Color.RED);
+            hasErrors = true;
+        } else {
+            username_text.setTextColor(Color.BLACK);
+        }
+
+        if (password_text.getText().toString().trim().length() == 0) {
+            password_text.setTextColor(Color.RED);
+            hasErrors = true;
+        } else {
+            password_text.setTextColor(Color.BLACK);
+        }
+        if (hasErrors) {
+            return;
+        }
+        showDialog(0);
+        mAuthThread = AuthUtils.attemptAuth(uri,
+                username_text.getText().toString(),
+                password_text.getText().toString(),
+                mHandler,
+                AuthenticatorActivity.this);
+    }
+}

+ 24 - 1
src/eu/alefzero/owncloud/ui/FileDetailActivity.java → src/eu/alefzero/owncloud/ui/activity/FileDetailActivity.java

@@ -1,4 +1,21 @@
-package eu.alefzero.owncloud.ui;
+/* ownCloud Android client application
+ *   Copyright (C) 2011  Bartek Przybylski
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package eu.alefzero.owncloud.ui.activity;
 
 
 import eu.alefzero.owncloud.R;
@@ -18,6 +35,12 @@ import android.util.Log;
 import android.view.View;
 import android.view.Window;
 
+/**
+ * This activity displays the details of a file like
+ * its name, its size and so on.
+ * @author Bartek Przybylski
+ *
+ */
 public class FileDetailActivity extends FragmentActivity {
   private FileDetail mFileDetail;
   

+ 8 - 2
src/eu/alefzero/owncloud/ui/FileDisplayActivity.java → src/eu/alefzero/owncloud/ui/activity/FileDisplayActivity.java

@@ -16,7 +16,7 @@
  *
  */
 
-package eu.alefzero.owncloud.ui;
+package eu.alefzero.owncloud.ui.activity;
 
 import java.io.File;
 import java.io.FileInputStream;
@@ -53,17 +53,23 @@ import android.view.Window;
 import android.widget.ImageView;
 import android.widget.ListView;
 import android.widget.TextView;
-import eu.alefzero.owncloud.DbHandler;
 import eu.alefzero.owncloud.R;
 import eu.alefzero.owncloud.R.id;
 import eu.alefzero.owncloud.R.layout;
 import eu.alefzero.owncloud.R.menu;
 import eu.alefzero.owncloud.R.string;
 import eu.alefzero.owncloud.authenticator.AccountAuthenticator;
+import eu.alefzero.owncloud.db.DbHandler;
 import eu.alefzero.owncloud.db.ProviderMeta.ProviderTableMeta;
 import eu.alefzero.owncloud.ui.fragment.FileDetail;
 import eu.alefzero.owncloud.ui.fragment.FileList;
 import eu.alefzero.owncloud.ui.fragment.ActionBar;
+
+/**
+ * Displays, what files the user has available in his ownCloud.
+ * @author Bartek Przybylski
+ *
+ */
 public class FileDisplayActivity extends FragmentActivity {
   private DbHandler mDBHandler;
   private Stack<String> mParents;

+ 3 - 3
src/eu/alefzero/owncloud/ui/LandingActivity.java → src/eu/alefzero/owncloud/ui/activity/LandingActivity.java

@@ -1,5 +1,5 @@
 /* ownCloud Android client application
- *   Copyright (C) 2012  Lennart Rosam
+ *   Copyright (C) 2011 Bartek Przybylski
  *
  *   This program is free software: you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License as published by
@@ -15,7 +15,7 @@
  *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  *
  */
-package eu.alefzero.owncloud.ui;
+package eu.alefzero.owncloud.ui.activity;
 
 import android.accounts.Account;
 import android.accounts.AccountManager;
@@ -31,8 +31,8 @@ import eu.alefzero.owncloud.authenticator.AccountAuthenticator;
 
 /**
  * This activity is used as a landing page when the user first opens this app.
- * 
  * @author Lennart Rosam
+ * 
  */
 public class LandingActivity extends FragmentActivity implements OnClickListener {
 

+ 168 - 146
src/eu/alefzero/owncloud/ui/Preferences.java → src/eu/alefzero/owncloud/ui/activity/Preferences.java

@@ -1,146 +1,168 @@
-package eu.alefzero.owncloud.ui;
-
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.Vector;
-
-import eu.alefzero.owncloud.DbHandler;
-import eu.alefzero.owncloud.OwnCloudSession;
-import eu.alefzero.owncloud.R;
-import eu.alefzero.owncloud.R.id;
-import eu.alefzero.owncloud.R.menu;
-import eu.alefzero.owncloud.R.xml;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.os.Bundle;
-import android.preference.Preference;
-import android.preference.PreferenceActivity;
-import android.preference.PreferenceScreen;
-import android.util.Log;
-import android.view.ContextMenu;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ContextMenu.ContextMenuInfo;
-import android.widget.AdapterView.AdapterContextMenuInfo;
-
-public class Preferences extends PreferenceActivity {
-  private String TAG = "OwnCloudPreferences";
-  private final int mNewSession = 47;
-  private final int mEditSession = 48;
-  private DbHandler mDbHandler;
-  private Vector<OwnCloudSession> mSessions;
-  private int mSelectedMenuItem;
-  
-  @Override
-  public void onCreate(Bundle savedInstanceState){
-    super.onCreate(savedInstanceState);
-    mDbHandler = new DbHandler(getBaseContext());
-    mSessions = new Vector<OwnCloudSession>();
-    addPreferencesFromResource(R.xml.preferences);
-    registerForContextMenu(getListView());
-    //populateSessionList();
-  }
-  
-  private void populateSessionList() {
-    mSessions.clear();
-    mSessions = mDbHandler.getSessionList();
-    PreferenceScreen ps = getPreferenceScreen();
-    ps.removeAll();
-    addPreferencesFromResource(R.xml.preferences);
-    for (int i = 0; i < mSessions.size(); i++) {
-      Preference preference = new Preference(getBaseContext());
-      preference.setTitle(mSessions.get(i).getName());
-      URI uri;
-      try {
-        uri = new URI(mSessions.get(i).getUrl());
-      } catch (URISyntaxException e) {
-        e.printStackTrace(); // should never happend
-        continue;
-      }
-      preference.setSummary(uri.getScheme() + "://" + uri.getHost()+uri.getPath());
-      ps.addPreference(preference);
-    }
-  }
-
-  @Override
-  public boolean onCreateOptionsMenu(Menu menu) {
-    super.onCreateOptionsMenu(menu);
-    MenuInflater inflater = getMenuInflater();
-    inflater.inflate(R.menu.prefs_menu, menu);
-    return true;
-  }
-  
-  @Override
-  public boolean onMenuItemSelected(int featureId, MenuItem item) {
-    super.onMenuItemSelected(featureId, item);
-    Intent intent;
-    
-    switch (item.getItemId()) {
-      case R.id.addSessionItem:
-        intent = new Intent(this, PreferencesNewSession.class);
-        startActivityForResult(intent, mNewSession);
-        break;
-      case R.id.SessionContextEdit:
-        intent = new Intent(this, PreferencesNewSession.class);
-        intent.putExtra("sessionId", mSessions.get(mSelectedMenuItem).getEntryId());
-        intent.putExtra("sessionName", mSessions.get(mSelectedMenuItem).getName());
-        intent.putExtra("sessionURL", mSessions.get(mSelectedMenuItem).getUrl());
-        startActivityForResult(intent, mEditSession);
-        break;
-      case R.id.SessionContextRemove:
-        OwnCloudSession ocs = mSessions.get(mSelectedMenuItem);
-        mDbHandler.removeSessionWithId(ocs.getEntryId());
-        mSessions.remove(ocs);
-        getPreferenceScreen().removePreference(getPreferenceScreen().getPreference(mSelectedMenuItem+1));
-        break;
-      default:
-        Log.w(TAG, "Unknown menu item triggered");
-        return false;
-    }
-    return true;
-  }
-
-  @Override
-  protected void onActivityResult(int requestCode, int resultCode, Intent data) {
-    super.onActivityResult(requestCode, resultCode, data);
-    if (resultCode == Activity.RESULT_OK) {
-      switch (requestCode) {
-        case mNewSession:
-          mDbHandler.addSession(data.getStringExtra("sessionName"), 
-                                data.getStringExtra("sessionURL"));
-          getPreferenceScreen().removeAll();
-          addPreferencesFromResource(R.xml.preferences);
-          populateSessionList();
-          break;
-        case mEditSession:
-          mDbHandler.changeSessionFields(data.getIntExtra("sessionId", -1),
-                                         data.getStringExtra("sessionName"),
-                                         data.getStringExtra("sessionURL"));
-          populateSessionList();
-          break;
-      }
-    }
-  }
-
-  @Override
-  public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
-    super.onCreateContextMenu(menu, v, menuInfo);
-    AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
-    mSelectedMenuItem = info.position-1;
-    menu.setHeaderTitle(mSessions.get(mSelectedMenuItem).getName());
-    
-    MenuInflater inflater = getMenuInflater();
-    inflater.inflate(R.menu.session_context_menu, menu);
-    
-  }
-  
-  @Override
-  protected void onDestroy() {
-    mDbHandler.close();
-    super.onDestroy();
-  }
-  
-}
+/* ownCloud Android client application
+ *   Copyright (C) 2011  Bartek Przybylski
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package eu.alefzero.owncloud.ui.activity;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Vector;
+
+import eu.alefzero.owncloud.OwnCloudSession;
+import eu.alefzero.owncloud.R;
+import eu.alefzero.owncloud.R.id;
+import eu.alefzero.owncloud.R.menu;
+import eu.alefzero.owncloud.R.xml;
+import eu.alefzero.owncloud.db.DbHandler;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.PreferenceActivity;
+import android.preference.PreferenceScreen;
+import android.util.Log;
+import android.view.ContextMenu;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ContextMenu.ContextMenuInfo;
+import android.widget.AdapterView.AdapterContextMenuInfo;
+
+/**
+ * An Activity that allows the user to change the application's settings.
+ * @author Bartek Przybylski
+ *
+ */
+public class Preferences extends PreferenceActivity {
+  private String TAG = "OwnCloudPreferences";
+  private final int mNewSession = 47;
+  private final int mEditSession = 48;
+  private DbHandler mDbHandler;
+  private Vector<OwnCloudSession> mSessions;
+  private int mSelectedMenuItem;
+  
+  @Override
+  public void onCreate(Bundle savedInstanceState){
+    super.onCreate(savedInstanceState);
+    mDbHandler = new DbHandler(getBaseContext());
+    mSessions = new Vector<OwnCloudSession>();
+    addPreferencesFromResource(R.xml.preferences);
+    registerForContextMenu(getListView());
+    //populateSessionList();
+  }
+  
+  private void populateSessionList() {
+    mSessions.clear();
+    mSessions = mDbHandler.getSessionList();
+    PreferenceScreen ps = getPreferenceScreen();
+    ps.removeAll();
+    addPreferencesFromResource(R.xml.preferences);
+    for (int i = 0; i < mSessions.size(); i++) {
+      Preference preference = new Preference(getBaseContext());
+      preference.setTitle(mSessions.get(i).getName());
+      URI uri;
+      try {
+        uri = new URI(mSessions.get(i).getUrl());
+      } catch (URISyntaxException e) {
+        e.printStackTrace(); // should never happend
+        continue;
+      }
+      preference.setSummary(uri.getScheme() + "://" + uri.getHost()+uri.getPath());
+      ps.addPreference(preference);
+    }
+  }
+
+  @Override
+  public boolean onCreateOptionsMenu(Menu menu) {
+    super.onCreateOptionsMenu(menu);
+    MenuInflater inflater = getMenuInflater();
+    inflater.inflate(R.menu.prefs_menu, menu);
+    return true;
+  }
+  
+  @Override
+  public boolean onMenuItemSelected(int featureId, MenuItem item) {
+    super.onMenuItemSelected(featureId, item);
+    Intent intent;
+    
+    switch (item.getItemId()) {
+      case R.id.addSessionItem:
+        intent = new Intent(this, PreferencesNewSession.class);
+        startActivityForResult(intent, mNewSession);
+        break;
+      case R.id.SessionContextEdit:
+        intent = new Intent(this, PreferencesNewSession.class);
+        intent.putExtra("sessionId", mSessions.get(mSelectedMenuItem).getEntryId());
+        intent.putExtra("sessionName", mSessions.get(mSelectedMenuItem).getName());
+        intent.putExtra("sessionURL", mSessions.get(mSelectedMenuItem).getUrl());
+        startActivityForResult(intent, mEditSession);
+        break;
+      case R.id.SessionContextRemove:
+        OwnCloudSession ocs = mSessions.get(mSelectedMenuItem);
+        mDbHandler.removeSessionWithId(ocs.getEntryId());
+        mSessions.remove(ocs);
+        getPreferenceScreen().removePreference(getPreferenceScreen().getPreference(mSelectedMenuItem+1));
+        break;
+      default:
+        Log.w(TAG, "Unknown menu item triggered");
+        return false;
+    }
+    return true;
+  }
+
+  @Override
+  protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+    super.onActivityResult(requestCode, resultCode, data);
+    if (resultCode == Activity.RESULT_OK) {
+      switch (requestCode) {
+        case mNewSession:
+          mDbHandler.addSession(data.getStringExtra("sessionName"), 
+                                data.getStringExtra("sessionURL"));
+          getPreferenceScreen().removeAll();
+          addPreferencesFromResource(R.xml.preferences);
+          populateSessionList();
+          break;
+        case mEditSession:
+          mDbHandler.changeSessionFields(data.getIntExtra("sessionId", -1),
+                                         data.getStringExtra("sessionName"),
+                                         data.getStringExtra("sessionURL"));
+          populateSessionList();
+          break;
+      }
+    }
+  }
+
+  @Override
+  public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
+    super.onCreateContextMenu(menu, v, menuInfo);
+    AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
+    mSelectedMenuItem = info.position-1;
+    menu.setHeaderTitle(mSessions.get(mSelectedMenuItem).getName());
+    
+    MenuInflater inflater = getMenuInflater();
+    inflater.inflate(R.menu.session_context_menu, menu);
+    
+  }
+  
+  @Override
+  protected void onDestroy() {
+    mDbHandler.close();
+    super.onDestroy();
+  }
+  
+}

+ 143 - 143
src/eu/alefzero/owncloud/ui/PreferencesNewSession.java → src/eu/alefzero/owncloud/ui/activity/PreferencesNewSession.java

@@ -1,143 +1,143 @@
-package eu.alefzero.owncloud.ui;
-
-import java.net.URI;
-import java.net.URISyntaxException;
-
-import eu.alefzero.owncloud.authenticator.AccountAuthenticatorService;
-
-import android.accounts.Account;
-import android.accounts.AccountAuthenticatorActivity;
-import android.accounts.AccountManager;
-import android.app.Activity;
-import android.content.Intent;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.Toast;
-
-public class PreferencesNewSession extends AccountAuthenticatorActivity implements OnClickListener {
-  private Intent mReturnData;
-  private final String TAG = "OwnCloudPreferencesNewSession";
-  @Override
-  public void onCreate(Bundle savedInstanceState){
-    super.onCreate(savedInstanceState);
-    //setContentView(R.layout.add_new_session);
-    /*
-    EditText et;// = (EditText) findViewById(R.id.newSession_sessionName);
-    
-    et = (EditText) findViewById(R.id.newSession_URL);
-    if (getIntent().hasExtra("sessionURL")) {
-      try {
-        URI uri = new URI(getIntent().getStringExtra("sessionURL"));
-        String url = uri.getHost();
-        if (uri.getPort() != -1) {
-          url += ":" + String.valueOf(uri.getPort());
-        }
-        if (uri.getPath() != null) {
-          url += uri.getPath();
-        } else {
-          url += "/";
-        }
-        et.setText(url);
-        et = (EditText) findViewById(R.id.newSession_username);
-        if (uri.getAuthority() != null) {
-          if (uri.getUserInfo().indexOf(':') != -1) {
-            et.setText(uri.getUserInfo().substring(0, uri.getUserInfo().indexOf(':')));
-            et = (EditText) findViewById(R.id.newSession_password);
-            et.setText(uri.getUserInfo().substring(uri.getUserInfo().indexOf(':')+1));
-          } else {
-            et.setText(uri.getUserInfo());
-          }
-        }
-        
-      } catch (URISyntaxException e) {
-        Log.e(TAG, "Incorrect URI syntax " + e.getLocalizedMessage());
-      }
-    }
-    
-    mReturnData = new Intent();
-    setResult(Activity.RESULT_OK, mReturnData);
-    ((Button) findViewById(R.id.button1)).setOnClickListener(this);
-    ((Button) findViewById(R.id.button2)).setOnClickListener(this);*/
-  }
-  
-  @Override
-  protected void onResume() {
-    super.onResume();
-  }
-
-  public void onClick(View v) {
-   /* switch (v.getId()) {
-      case R.id.button1:
-        Intent intent = new Intent();
-        if (getIntent().hasExtra("sessionId")) {
-          intent.putExtra("sessionId", getIntent().getIntExtra("sessionId", -1));
-        }
-        //String sessionName = ((EditText) findViewById(R.id.newSession_sessionName)).getText().toString();
-      //  if (sessionName.trim().equals("") || !isNameValid(sessionName)) {
-     //    Toast.makeText(this, R.string.new_session_session_name_error, Toast.LENGTH_LONG).show();
-     //     break;
-       // }
-        URI uri = prepareURI();
-        if (uri != null) {
-          //intent.putExtra("sessionName", sessionName);
-          intent.putExtra("sessionURL", uri.toString());
-          setResult(Activity.RESULT_OK, intent);
-          AccountManager accMgr = AccountManager.get(this);
-          Account a = new Account("OwnCloud", AccountAuthenticatorService.ACCOUNT_TYPE);
-          accMgr.addAccountExplicitly(a, "asd", null);
-          finish();
-        }
-        break;
-      case R.id.button2:
-        setResult(Activity.RESULT_CANCELED);
-        finish();
-        break;
-    }*/
-  }
-  
-  private URI prepareURI() {
-    URI uri = null;
-   /* String url = "";
-    try {
-      String username = ((EditText) findViewById(R.id.newSession_username)).getText().toString().trim();
-      String password = ((EditText) findViewById(R.id.newSession_password)).getText().toString().trim();
-      String hostname = ((EditText) findViewById(R.id.newSession_URL)).getText().toString().trim();
-      String scheme;
-      if (hostname.matches("[A-Za-z]://")) {
-        scheme = hostname.substring(0, hostname.indexOf("://")+3);
-        hostname = hostname.substring(hostname.indexOf("://")+3);
-      } else {
-        scheme = "http://";
-      }
-      if (!username.equals("")) {
-        if (!password.equals("")) {
-          username += ":" + password + "@";
-        } else {
-          username += "@";
-        }
-      }
-      url = scheme + username + hostname;
-      Log.i(TAG, url);
-      uri = new URI(url);
-    } catch (URISyntaxException e) {
-      Log.e(TAG, "Incorrect URI syntax " + e.getLocalizedMessage());
-      Toast.makeText(this, R.string.new_session_uri_error, Toast.LENGTH_LONG).show();
-    }
-    */return uri;
-  }
-  
-  private boolean isNameValid(String string) {
-    return string.matches("[A-Za-z0-9 _-]*");
-  }
-  
-  @Override
-  public void onBackPressed() {
-    setResult(Activity.RESULT_CANCELED);
-    super.onBackPressed();
-  }
-  
-}
+package eu.alefzero.owncloud.ui.activity;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import eu.alefzero.owncloud.authenticator.AccountAuthenticatorService;
+
+import android.accounts.Account;
+import android.accounts.AccountAuthenticatorActivity;
+import android.accounts.AccountManager;
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.Toast;
+
+public class PreferencesNewSession extends AccountAuthenticatorActivity implements OnClickListener {
+  private Intent mReturnData;
+  private final String TAG = "OwnCloudPreferencesNewSession";
+  @Override
+  public void onCreate(Bundle savedInstanceState){
+    super.onCreate(savedInstanceState);
+    //setContentView(R.layout.add_new_session);
+    /*
+    EditText et;// = (EditText) findViewById(R.id.newSession_sessionName);
+    
+    et = (EditText) findViewById(R.id.newSession_URL);
+    if (getIntent().hasExtra("sessionURL")) {
+      try {
+        URI uri = new URI(getIntent().getStringExtra("sessionURL"));
+        String url = uri.getHost();
+        if (uri.getPort() != -1) {
+          url += ":" + String.valueOf(uri.getPort());
+        }
+        if (uri.getPath() != null) {
+          url += uri.getPath();
+        } else {
+          url += "/";
+        }
+        et.setText(url);
+        et = (EditText) findViewById(R.id.newSession_username);
+        if (uri.getAuthority() != null) {
+          if (uri.getUserInfo().indexOf(':') != -1) {
+            et.setText(uri.getUserInfo().substring(0, uri.getUserInfo().indexOf(':')));
+            et = (EditText) findViewById(R.id.newSession_password);
+            et.setText(uri.getUserInfo().substring(uri.getUserInfo().indexOf(':')+1));
+          } else {
+            et.setText(uri.getUserInfo());
+          }
+        }
+        
+      } catch (URISyntaxException e) {
+        Log.e(TAG, "Incorrect URI syntax " + e.getLocalizedMessage());
+      }
+    }
+    
+    mReturnData = new Intent();
+    setResult(Activity.RESULT_OK, mReturnData);
+    ((Button) findViewById(R.id.button1)).setOnClickListener(this);
+    ((Button) findViewById(R.id.button2)).setOnClickListener(this);*/
+  }
+  
+  @Override
+  protected void onResume() {
+    super.onResume();
+  }
+
+  public void onClick(View v) {
+   /* switch (v.getId()) {
+      case R.id.button1:
+        Intent intent = new Intent();
+        if (getIntent().hasExtra("sessionId")) {
+          intent.putExtra("sessionId", getIntent().getIntExtra("sessionId", -1));
+        }
+        //String sessionName = ((EditText) findViewById(R.id.newSession_sessionName)).getText().toString();
+      //  if (sessionName.trim().equals("") || !isNameValid(sessionName)) {
+     //    Toast.makeText(this, R.string.new_session_session_name_error, Toast.LENGTH_LONG).show();
+     //     break;
+       // }
+        URI uri = prepareURI();
+        if (uri != null) {
+          //intent.putExtra("sessionName", sessionName);
+          intent.putExtra("sessionURL", uri.toString());
+          setResult(Activity.RESULT_OK, intent);
+          AccountManager accMgr = AccountManager.get(this);
+          Account a = new Account("OwnCloud", AccountAuthenticatorService.ACCOUNT_TYPE);
+          accMgr.addAccountExplicitly(a, "asd", null);
+          finish();
+        }
+        break;
+      case R.id.button2:
+        setResult(Activity.RESULT_CANCELED);
+        finish();
+        break;
+    }*/
+  }
+  
+  private URI prepareURI() {
+    URI uri = null;
+   /* String url = "";
+    try {
+      String username = ((EditText) findViewById(R.id.newSession_username)).getText().toString().trim();
+      String password = ((EditText) findViewById(R.id.newSession_password)).getText().toString().trim();
+      String hostname = ((EditText) findViewById(R.id.newSession_URL)).getText().toString().trim();
+      String scheme;
+      if (hostname.matches("[A-Za-z]://")) {
+        scheme = hostname.substring(0, hostname.indexOf("://")+3);
+        hostname = hostname.substring(hostname.indexOf("://")+3);
+      } else {
+        scheme = "http://";
+      }
+      if (!username.equals("")) {
+        if (!password.equals("")) {
+          username += ":" + password + "@";
+        } else {
+          username += "@";
+        }
+      }
+      url = scheme + username + hostname;
+      Log.i(TAG, url);
+      uri = new URI(url);
+    } catch (URISyntaxException e) {
+      Log.e(TAG, "Incorrect URI syntax " + e.getLocalizedMessage());
+      Toast.makeText(this, R.string.new_session_uri_error, Toast.LENGTH_LONG).show();
+    }
+    */return uri;
+  }
+  
+  private boolean isNameValid(String string) {
+    return string.matches("[A-Za-z0-9 _-]*");
+  }
+  
+  @Override
+  public void onBackPressed() {
+    setResult(Activity.RESULT_CANCELED);
+    super.onBackPressed();
+  }
+  
+}

+ 131 - 108
src/eu/alefzero/owncloud/ui/adapter/FileListListAdapter.java

@@ -1,108 +1,131 @@
-package eu.alefzero.owncloud.ui.adapter;
-
-import java.security.Provider;
-
-import eu.alefzero.owncloud.DisplayUtils;
-import eu.alefzero.owncloud.R;
-import eu.alefzero.owncloud.R.drawable;
-import eu.alefzero.owncloud.R.id;
-import eu.alefzero.owncloud.R.layout;
-import eu.alefzero.owncloud.db.ProviderMeta;
-import eu.alefzero.owncloud.db.ProviderMeta.ProviderTableMeta;
-
-import android.content.Context;
-import android.database.Cursor;
-import android.database.DataSetObserver;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.View.OnLongClickListener;
-import android.widget.AdapterView;
-import android.widget.ImageView;
-import android.widget.ListAdapter;
-import android.widget.TextView;
-import android.widget.AdapterView.OnItemClickListener;
-
-public class FileListListAdapter implements ListAdapter {
-
-  private Cursor mCursor;
-  private Context mContext;
-  
-  public FileListListAdapter(Cursor c, Context context) {
-    mCursor = c;
-    mContext = context;
-  }
-  
-  public boolean areAllItemsEnabled() {
-    return true;
-  }
-
-  public boolean isEnabled(int position) {
-    // TODO Auto-generated method stub
-    return true;
-  }
-
-  public int getCount() {
-    // TODO Auto-generated method stub
-    return mCursor.getCount();
-  }
-
-  public Object getItem(int position) {
-    // TODO Auto-generated method stub
-    return null;
-  }
-
-  public long getItemId(int position) {
-    // TODO Auto-generated method stub
-    return 0;
-  }
-
-  public int getItemViewType(int position) {
-    // TODO Auto-generated method stub
-    return 0;
-  }
-
-  public View getView(int position, View convertView, ViewGroup parent) {
-    View v = convertView;
-    if (v == null) {
-      LayoutInflater vi = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-      v = vi.inflate(R.layout.list_layout, null);
-    }
-    if (mCursor.moveToPosition(position)) {
-      TextView tv = (TextView) v.findViewById(R.id.Filename);
-      tv.setText(DisplayUtils.HtmlDecode(mCursor.getString(mCursor.getColumnIndex(ProviderMeta.ProviderTableMeta.FILE_NAME))));
-      if (!mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_CONTENT_TYPE)).equals("DIR")) {
-        ImageView iv = (ImageView) v.findViewById(R.id.imageView1);
-        iv.setImageResource(R.drawable.file);
-      }
-    }
-    
-    return v;
-  }
-
-  public int getViewTypeCount() {
-    // TODO Auto-generated method stub
-    return 4;
-  }
-
-  public boolean hasStableIds() {
-    // TODO Auto-generated method stub
-    return true;
-  }
-
-  public boolean isEmpty() {
-    // TODO Auto-generated method stub
-    return false;
-  }
-
-  public void registerDataSetObserver(DataSetObserver observer) {
-    // TODO Auto-generated method stub
-    
-  }
-
-  public void unregisterDataSetObserver(DataSetObserver observer) {
-    // TODO Auto-generated method stub
-    
-  }
-}
+/* ownCloud Android client application
+ *   Copyright (C) 2011  Bartek Przybylski
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package eu.alefzero.owncloud.ui.adapter;
+
+import java.security.Provider;
+
+import eu.alefzero.owncloud.DisplayUtils;
+import eu.alefzero.owncloud.R;
+import eu.alefzero.owncloud.R.drawable;
+import eu.alefzero.owncloud.R.id;
+import eu.alefzero.owncloud.R.layout;
+import eu.alefzero.owncloud.db.ProviderMeta;
+import eu.alefzero.owncloud.db.ProviderMeta.ProviderTableMeta;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.database.DataSetObserver;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.View.OnLongClickListener;
+import android.widget.AdapterView;
+import android.widget.ImageView;
+import android.widget.ListAdapter;
+import android.widget.TextView;
+import android.widget.AdapterView.OnItemClickListener;
+
+/**
+ * This Adapter populates a ListView with all files and 
+ * folders in an ownCloud instance.
+ * @author Bartek Przybylski
+ *
+ */
+public class FileListListAdapter implements ListAdapter {
+
+  private Cursor mCursor;
+  private Context mContext;
+  
+  public FileListListAdapter(Cursor c, Context context) {
+    mCursor = c;
+    mContext = context;
+  }
+  
+  public boolean areAllItemsEnabled() {
+    return true;
+  }
+
+  public boolean isEnabled(int position) {
+    // TODO Auto-generated method stub
+    return true;
+  }
+
+  public int getCount() {
+    // TODO Auto-generated method stub
+    return mCursor.getCount();
+  }
+
+  public Object getItem(int position) {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  public long getItemId(int position) {
+    // TODO Auto-generated method stub
+    return 0;
+  }
+
+  public int getItemViewType(int position) {
+    // TODO Auto-generated method stub
+    return 0;
+  }
+
+  public View getView(int position, View convertView, ViewGroup parent) {
+    View v = convertView;
+    if (v == null) {
+      LayoutInflater vi = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+      v = vi.inflate(R.layout.list_layout, null);
+    }
+    if (mCursor.moveToPosition(position)) {
+      TextView tv = (TextView) v.findViewById(R.id.Filename);
+      tv.setText(DisplayUtils.HtmlDecode(mCursor.getString(mCursor.getColumnIndex(ProviderMeta.ProviderTableMeta.FILE_NAME))));
+      if (!mCursor.getString(mCursor.getColumnIndex(ProviderTableMeta.FILE_CONTENT_TYPE)).equals("DIR")) {
+        ImageView iv = (ImageView) v.findViewById(R.id.imageView1);
+        iv.setImageResource(R.drawable.file);
+      }
+    }
+    
+    return v;
+  }
+
+  public int getViewTypeCount() {
+    // TODO Auto-generated method stub
+    return 4;
+  }
+
+  public boolean hasStableIds() {
+    // TODO Auto-generated method stub
+    return true;
+  }
+
+  public boolean isEmpty() {
+    // TODO Auto-generated method stub
+    return false;
+  }
+
+  public void registerDataSetObserver(DataSetObserver observer) {
+    // TODO Auto-generated method stub
+    
+  }
+
+  public void unregisterDataSetObserver(DataSetObserver observer) {
+    // TODO Auto-generated method stub
+    
+  }
+}

+ 104 - 87
src/eu/alefzero/owncloud/ui/adapter/LandingScreenAdapter.java

@@ -1,87 +1,104 @@
-package eu.alefzero.owncloud.ui.adapter;
-
-import android.content.Context;
-import android.content.Intent;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
-import android.widget.ImageView;
-import android.widget.TextView;
-import eu.alefzero.owncloud.R;
-import eu.alefzero.owncloud.ui.FileDisplayActivity;
-import eu.alefzero.owncloud.ui.Preferences;
-
-/**
- * Populates the landing screen icons.
- * @author Benutzer
- *
- */
-public class LandingScreenAdapter extends BaseAdapter {
-	
-	private Context mContext;
-
-	private final Integer[] mLandingScreenIcons = { R.drawable.home,
-			R.drawable.music, R.drawable.contacts,
-			R.drawable.calendar,
-			android.R.drawable.ic_menu_agenda,
-			R.drawable.settings };
-
-	private final Integer[] mLandingScreenTexts = { R.string.main_files,
-			R.string.main_music, R.string.main_contacts,
-			R.string.main_calendar, R.string.main_bookmarks,
-			R.string.main_settings };
-
-	public LandingScreenAdapter(Context context) {
-		mContext = context;
-	}
-
-	@Override
-	public int getCount() {
-		return mLandingScreenIcons.length;
-	}
-
-	@Override
-	/**
-	 * Returns the Intent associated with this object
-	 * or null if the functionality is not yet implemented
-	 */
-	public Object getItem(int position) {
-		Intent intent = new Intent();
-		switch (position) {
-		case 0:
-			intent.setClass(mContext, FileDisplayActivity.class);
-			break;
-		case 5:
-			intent.setClass(mContext, Preferences.class);
-			break;
-		default:
-			intent = null;
-		}
-		return intent;
-	}
-
-	@Override
-	public long getItemId(int position) {
-		return position;
-	}
-
-	@Override
-	public View getView(int position, View convertView, ViewGroup parent) {
-		if (convertView == null) {
-			LayoutInflater inflator = LayoutInflater.from(mContext);
-			convertView = inflator
-					.inflate(R.layout.landing_page_item, null);
-
-			ImageView icon = (ImageView) convertView
-					.findViewById(R.id.gridImage);
-			TextView iconText = (TextView) convertView
-					.findViewById(R.id.gridText);
-
-			icon.setImageResource(mLandingScreenIcons[position]);
-			iconText.setText(mLandingScreenTexts[position]);
-		}
-		return convertView;
-	}
-
-}
+/* ownCloud Android client application
+ *   Copyright (C) 2011  Bartek Przybylski
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package eu.alefzero.owncloud.ui.adapter;
+
+import android.content.Context;
+import android.content.Intent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.ImageView;
+import android.widget.TextView;
+import eu.alefzero.owncloud.R;
+import eu.alefzero.owncloud.ui.activity.FileDisplayActivity;
+import eu.alefzero.owncloud.ui.activity.Preferences;
+
+/**
+ * Populates the landing screen icons.
+ * @author Lennart Rosam
+ *
+ */
+public class LandingScreenAdapter extends BaseAdapter {
+	
+	private Context mContext;
+
+	private final Integer[] mLandingScreenIcons = { R.drawable.home,
+			R.drawable.music, R.drawable.contacts,
+			R.drawable.calendar,
+			android.R.drawable.ic_menu_agenda,
+			R.drawable.settings };
+
+	private final Integer[] mLandingScreenTexts = { R.string.main_files,
+			R.string.main_music, R.string.main_contacts,
+			R.string.main_calendar, R.string.main_bookmarks,
+			R.string.main_settings };
+
+	public LandingScreenAdapter(Context context) {
+		mContext = context;
+	}
+
+	@Override
+	public int getCount() {
+		return mLandingScreenIcons.length;
+	}
+
+	@Override
+	/**
+	 * Returns the Intent associated with this object
+	 * or null if the functionality is not yet implemented
+	 */
+	public Object getItem(int position) {
+		Intent intent = new Intent();
+		switch (position) {
+		case 0:
+			intent.setClass(mContext, FileDisplayActivity.class);
+			break;
+		case 5:
+			intent.setClass(mContext, Preferences.class);
+			break;
+		default:
+			intent = null;
+		}
+		return intent;
+	}
+
+	@Override
+	public long getItemId(int position) {
+		return position;
+	}
+
+	@Override
+	public View getView(int position, View convertView, ViewGroup parent) {
+		if (convertView == null) {
+			LayoutInflater inflator = LayoutInflater.from(mContext);
+			convertView = inflator
+					.inflate(R.layout.landing_page_item, null);
+
+			ImageView icon = (ImageView) convertView
+					.findViewById(R.id.gridImage);
+			TextView iconText = (TextView) convertView
+					.findViewById(R.id.gridText);
+
+			icon.setImageResource(mLandingScreenIcons[position]);
+			iconText.setText(mLandingScreenTexts[position]);
+		}
+		return convertView;
+	}
+
+}

+ 66 - 45
src/eu/alefzero/owncloud/ui/fragment/ActionBar.java

@@ -1,45 +1,66 @@
-package eu.alefzero.owncloud.ui.fragment;
-
-import eu.alefzero.owncloud.PathLayout;
-import eu.alefzero.owncloud.R;
-import android.app.Activity;
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-
-public class ActionBar extends Fragment {
-
-  @Override
-  public void onCreate(Bundle savedInstanceState) {
-    super.onCreate(savedInstanceState);
-    
-  }
-  @Override
-  public View onCreateView(LayoutInflater inflater, ViewGroup container,
-      Bundle savedInstanceState) {
-    View v = inflater.inflate(R.layout.action_bar, container, false);
-    return v;
-  }
-  
-  @Override
-  public void onAttach(Activity activity) {
-    super.onAttach(activity);
-  }
-  
-  public void setPath(String path) {
-    if (getPathLayout() != null)
-      getPathLayout().addPath(path);
-  }
-  
-  public String getCurrentPath() {
-    if (getPathLayout() != null)
-       return getPathLayout().getFullPath();
-    return "";
-  }
-  
-  private PathLayout getPathLayout() {
-    return (PathLayout) getActivity().findViewById(R.id.pathLayout1);
-  }
-}
+/* ownCloud Android client application
+ *   Copyright (C) 2011  Bartek Przybylski
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package eu.alefzero.owncloud.ui.fragment;
+
+import eu.alefzero.owncloud.R;
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * A custom ActionBar implementation used in the FileDisplayActivity
+ * @author Bartek Przybylski
+ *
+ */
+public class ActionBar extends Fragment {
+
+  @Override
+  public void onCreate(Bundle savedInstanceState) {
+    super.onCreate(savedInstanceState);
+    
+  }
+  @Override
+  public View onCreateView(LayoutInflater inflater, ViewGroup container,
+      Bundle savedInstanceState) {
+    View v = inflater.inflate(R.layout.action_bar, container, false);
+    return v;
+  }
+  
+  @Override
+  public void onAttach(Activity activity) {
+    super.onAttach(activity);
+  }
+  
+  public void setPath(String path) {
+    if (getPathLayout() != null)
+      getPathLayout().addPath(path);
+  }
+  
+  public String getCurrentPath() {
+    if (getPathLayout() != null)
+       return getPathLayout().getFullPath();
+    return "";
+  }
+  
+  private PathLayout getPathLayout() {
+    return (PathLayout) getActivity().findViewById(R.id.pathLayout1);
+  }
+}

+ 22 - 0
src/eu/alefzero/owncloud/ui/fragment/FileDetail.java

@@ -1,3 +1,20 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2011  Bartek Przybylski
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
 package eu.alefzero.owncloud.ui.fragment;
 
 import eu.alefzero.owncloud.R;
@@ -13,6 +30,11 @@ import android.view.ViewGroup;
 import android.widget.TextView;
 import android.widget.Toast;
 
+/**
+ * This Fragment is used to display the details about a file.
+ * @author Bartek Przybylski
+ *
+ */
 public class FileDetail extends Fragment {
   
   public Intent mIntent;

+ 23 - 1
src/eu/alefzero/owncloud/ui/fragment/FileList.java

@@ -1,10 +1,27 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2011  Bartek Przybylski
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
 package eu.alefzero.owncloud.ui.fragment;
 
 import eu.alefzero.owncloud.R;
 import eu.alefzero.owncloud.R.id;
 import eu.alefzero.owncloud.authenticator.AccountAuthenticator;
 import eu.alefzero.owncloud.db.ProviderMeta.ProviderTableMeta;
-import eu.alefzero.owncloud.ui.FileDetailActivity;
+import eu.alefzero.owncloud.ui.activity.FileDetailActivity;
 import eu.alefzero.owncloud.ui.adapter.FileListListAdapter;
 import eu.alefzero.owncloud.ui.fragment.ActionBar;
 import android.accounts.Account;
@@ -25,6 +42,11 @@ import android.widget.ListView;
 import android.widget.TextView;
 import android.widget.Toast;
 
+/**
+ * A Fragment that lists all files and folders in a given path.
+ * @author Bartek Przybylski
+ *
+ */
 public class FileList extends ListFragment {
   private Cursor mCursor;
   private Account mAccount;

+ 24 - 0
src/eu/alefzero/owncloud/ui/fragment/LandingPageFragment.java

@@ -1,3 +1,20 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2011  Bartek Przybylski
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
 package eu.alefzero.owncloud.ui.fragment;
 
 import android.content.Intent;
@@ -13,6 +30,13 @@ import android.widget.Toast;
 import eu.alefzero.owncloud.R;
 import eu.alefzero.owncloud.ui.adapter.LandingScreenAdapter;
 
+/**
+ * Used on the Landing page to display what Components of 
+ * the ownCloud there are. Like Files, Music, Contacts, etc.
+ * 
+ * @author Lennart Rosam
+ *
+ */
 public class LandingPageFragment extends Fragment implements OnItemClickListener {
 
 	@Override

+ 117 - 92
src/eu/alefzero/owncloud/PathLayout.java → src/eu/alefzero/owncloud/ui/fragment/PathLayout.java

@@ -1,92 +1,117 @@
-package eu.alefzero.owncloud;
-
-import java.util.LinkedList;
-import java.util.Stack;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.widget.HorizontalScrollView;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.ScrollView;
-import android.widget.TextView;
-
-public class PathLayout extends LinearLayout {
-
-  private LinkedList<String> paths;
-  ScrollView internalScroll;
-  LinearLayout view;
-
-  public PathLayout(Context context) {
-    super(context);
-    initialize();
-  }
-  
-  public PathLayout(Context context, AttributeSet attrs) {
-    super(context, attrs);
-    initialize();
-  }
-
-  public String pop() {
-    if (paths.size() == 0) {
-      return null;
-    }
-    int start = paths.size()*2-2;
-    int count = 2;
-    if (paths.size() == 1) {
-      start++;
-      count--;
-    }
-    view.removeViews(start, count);
-    return paths.removeLast();
-  }
-
-  public void addPath(String path) {
-    for (String s : path.split("/")) if (s.length() != 0) push(s);
-  }
-  
-  public void push(String path) {
-    // its weird that we cannot declare static imgView as path separator
-    if (paths.size() != 0) {
-      ImageView iv = new ImageView(getContext());
-      iv.setImageDrawable(getResources().getDrawable(R.drawable.breadcrumb));
-      iv.setPadding(2, 0, 2, 0);
-      view.addView(iv);
-    }
-    TextView tv = new TextView(getContext());
-    tv.setLayoutParams(getLayoutParams());
-    tv.setText(path);
-    view.addView(tv);
-    HorizontalScrollView hsv = (HorizontalScrollView) internalScroll.getChildAt(0);
-    hsv.smoothScrollTo(hsv.getMaxScrollAmount()*2, 0);
-    paths.addLast(path);
-  }
-  
-  public String peek() {
-    return paths.peek();
-  }
-
-  public String getFullPath() {
-    String ret = new String();
-    for (int i = 0; i < paths.size(); i++) {
-      ret += "/" + paths.get(i);
-    }
-    return ret;
-  }
-  
-  private void initialize() {
-    paths = new LinkedList<String>();
-    internalScroll = new ScrollView(getContext());
-    internalScroll.setFillViewport(true);
-    HorizontalScrollView hsv = new HorizontalScrollView(getContext());
-    hsv.setSmoothScrollingEnabled(true);
-    internalScroll.addView(hsv);
-    view = new LinearLayout(getContext());
-    addView(internalScroll);
-    hsv.addView(view);
-    ImageView iv = new ImageView(getContext());
-    iv.setImageDrawable(getResources().getDrawable(R.drawable.breadcrumb));
-    view.addView(iv);
-  }
-
-}
+/* ownCloud Android client application
+ *   Copyright (C) 2011  Bartek Przybylski
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package eu.alefzero.owncloud.ui.fragment;
+
+import java.util.LinkedList;
+import java.util.Stack;
+
+import eu.alefzero.owncloud.R;
+import eu.alefzero.owncloud.R.drawable;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.HorizontalScrollView;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+import android.widget.TextView;
+
+/**
+ * Part of the ActionBar Layout
+ * @author Bartek Przybylski
+ *
+ */
+public class PathLayout extends LinearLayout {
+
+  private LinkedList<String> paths;
+  ScrollView internalScroll;
+  LinearLayout view;
+
+  public PathLayout(Context context) {
+    super(context);
+    initialize();
+  }
+  
+  public PathLayout(Context context, AttributeSet attrs) {
+    super(context, attrs);
+    initialize();
+  }
+
+  public String pop() {
+    if (paths.size() == 0) {
+      return null;
+    }
+    int start = paths.size()*2-2;
+    int count = 2;
+    if (paths.size() == 1) {
+      start++;
+      count--;
+    }
+    view.removeViews(start, count);
+    return paths.removeLast();
+  }
+
+  public void addPath(String path) {
+    for (String s : path.split("/")) if (s.length() != 0) push(s);
+  }
+  
+  public void push(String path) {
+    // its weird that we cannot declare static imgView as path separator
+    if (paths.size() != 0) {
+      ImageView iv = new ImageView(getContext());
+      iv.setImageDrawable(getResources().getDrawable(R.drawable.breadcrumb));
+      iv.setPadding(2, 0, 2, 0);
+      view.addView(iv);
+    }
+    TextView tv = new TextView(getContext());
+    tv.setLayoutParams(getLayoutParams());
+    tv.setText(path);
+    view.addView(tv);
+    HorizontalScrollView hsv = (HorizontalScrollView) internalScroll.getChildAt(0);
+    hsv.smoothScrollTo(hsv.getMaxScrollAmount()*2, 0);
+    paths.addLast(path);
+  }
+  
+  public String peek() {
+    return paths.peek();
+  }
+
+  public String getFullPath() {
+    String ret = new String();
+    for (int i = 0; i < paths.size(); i++) {
+      ret += "/" + paths.get(i);
+    }
+    return ret;
+  }
+  
+  private void initialize() {
+    paths = new LinkedList<String>();
+    internalScroll = new ScrollView(getContext());
+    internalScroll.setFillViewport(true);
+    HorizontalScrollView hsv = new HorizontalScrollView(getContext());
+    hsv.setSmoothScrollingEnabled(true);
+    internalScroll.addView(hsv);
+    view = new LinearLayout(getContext());
+    addView(internalScroll);
+    hsv.addView(view);
+    ImageView iv = new ImageView(getContext());
+    iv.setImageDrawable(getResources().getDrawable(R.drawable.breadcrumb));
+    view.addView(iv);
+  }
+
+}

+ 36 - 19
src/eu/alefzero/webdav/HttpMkCol.java

@@ -1,19 +1,36 @@
-package eu.alefzero.webdav;
-
-import java.net.URI;
-
-import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
-
-public class HttpMkCol extends HttpEntityEnclosingRequestBase {
-
-  public final static String METHOD_NAME = "MKCOL";
-  
-  public HttpMkCol(final String uri) {
-    setURI(URI.create(uri));
-  }
-
-  @Override
-  public String getMethod() {
-    return METHOD_NAME;
-  }
-}
+/* ownCloud Android client application
+ *   Copyright (C) 2011  Bartek Przybylski
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package eu.alefzero.webdav;
+
+import java.net.URI;
+
+import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
+
+public class HttpMkCol extends HttpEntityEnclosingRequestBase {
+
+  public final static String METHOD_NAME = "MKCOL";
+  
+  public HttpMkCol(final String uri) {
+    setURI(URI.create(uri));
+  }
+
+  @Override
+  public String getMethod() {
+    return METHOD_NAME;
+  }
+}

+ 49 - 32
src/eu/alefzero/webdav/HttpPropFind.java

@@ -1,32 +1,49 @@
-package eu.alefzero.webdav;
-
-import java.net.URI;
-
-import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
-import org.apache.http.protocol.HTTP;
-
-public class HttpPropFind extends HttpEntityEnclosingRequestBase {
-
-  public final static String METHOD_NAME = "PROPFIND";
-  
-  public HttpPropFind(final URI uri) {
-    super();
-    setURI(uri);
-  }
-
-  public HttpPropFind(final String uri) {
-    this.setDepth("1");
-    setURI(URI.create(uri));
-    this.setHeader(HTTP.CONTENT_TYPE, "text/xml" + HTTP.CHARSET_PARAM + HTTP.UTF_8.toLowerCase());
-  }
-  
-  @Override
-  public String getMethod() {
-    return METHOD_NAME;
-  }
-  
-  public void setDepth(String depth) {
-    this.setHeader("Depth", depth);
-  }
-  
-}
+/* ownCloud Android client application
+ *   Copyright (C) 2011  Bartek Przybylski
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package eu.alefzero.webdav;
+
+import java.net.URI;
+
+import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
+import org.apache.http.protocol.HTTP;
+
+public class HttpPropFind extends HttpEntityEnclosingRequestBase {
+
+  public final static String METHOD_NAME = "PROPFIND";
+  
+  public HttpPropFind(final URI uri) {
+    super();
+    setURI(uri);
+  }
+
+  public HttpPropFind(final String uri) {
+    this.setDepth("1");
+    setURI(URI.create(uri));
+    this.setHeader(HTTP.CONTENT_TYPE, "text/xml" + HTTP.CHARSET_PARAM + HTTP.UTF_8.toLowerCase());
+  }
+  
+  @Override
+  public String getMethod() {
+    return METHOD_NAME;
+  }
+  
+  public void setDepth(String depth) {
+    this.setHeader("Depth", depth);
+  }
+  
+}

+ 43 - 26
src/eu/alefzero/webdav/HttpPropPatch.java

@@ -1,26 +1,43 @@
-package eu.alefzero.webdav;
-
-import java.net.URI;
-
-import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
-
-public class HttpPropPatch extends HttpEntityEnclosingRequestBase {
-
-  public static final String METHOD_NAME = "PROPPATCH";
-  
-  public HttpPropPatch(URI uri) {
-    super();
-    setURI(uri);
-  }
-  
-  public HttpPropPatch(final String uri) {
-    super();
-    setURI(URI.create(uri));
-  }
-  
-  @Override
-  public String getMethod() {
-    return METHOD_NAME;
-  }
-  
-}
+/* ownCloud Android client application
+ *   Copyright (C) 2011  Bartek Przybylski
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package eu.alefzero.webdav;
+
+import java.net.URI;
+
+import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
+
+public class HttpPropPatch extends HttpEntityEnclosingRequestBase {
+
+  public static final String METHOD_NAME = "PROPPATCH";
+  
+  public HttpPropPatch(URI uri) {
+    super();
+    setURI(uri);
+  }
+  
+  public HttpPropPatch(final String uri) {
+    super();
+    setURI(URI.create(uri));
+  }
+  
+  @Override
+  public String getMethod() {
+    return METHOD_NAME;
+  }
+  
+}

+ 38 - 21
src/eu/alefzero/webdav/TreeNodeContainer.java

@@ -1,21 +1,38 @@
-package eu.alefzero.webdav;
-
-import java.util.List;
-import java.util.ListIterator;
-
-import org.w3c.dom.Document;
-
-import android.util.Xml;
-
-public class TreeNodeContainer extends TreeNode {
-  
-  @Override
-  void refreshData(Document document) {
-    ListIterator<TreeNode> iterator = children_.listIterator();
-    while (iterator.hasNext()) {
-      iterator.next().refreshData(document);
-    }
-  }
-  
-  private List<TreeNode> children_;
-}
+/* ownCloud Android client application
+ *   Copyright (C) 2011  Bartek Przybylski
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package eu.alefzero.webdav;
+
+import java.util.List;
+import java.util.ListIterator;
+
+import org.w3c.dom.Document;
+
+import android.util.Xml;
+
+public class TreeNodeContainer extends TreeNode {
+  
+  @Override
+  void refreshData(Document document) {
+    ListIterator<TreeNode> iterator = children_.listIterator();
+    while (iterator.hasNext()) {
+      iterator.next().refreshData(document);
+    }
+  }
+  
+  private List<TreeNode> children_;
+}

+ 196 - 175
src/eu/alefzero/owncloud/WebdavClient.java → src/eu/alefzero/webdav/WebdavClient.java

@@ -1,175 +1,196 @@
-package eu.alefzero.owncloud;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.OutputStreamWriter;
-
-import org.apache.http.HttpHost;
-import org.apache.http.HttpResponse;
-import org.apache.http.HttpStatus;
-import org.apache.http.HttpVersion;
-import org.apache.http.auth.AuthScope;
-import org.apache.http.auth.UsernamePasswordCredentials;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.client.methods.HttpPut;
-import org.apache.http.conn.ClientConnectionManager;
-import org.apache.http.conn.params.ConnManagerPNames;
-import org.apache.http.conn.params.ConnPerRouteBean;
-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.FileEntity;
-import org.apache.http.entity.mime.content.FileBody;
-import org.apache.http.impl.auth.BasicScheme;
-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.BasicHttpContext;
-
-import eu.alefzero.owncloud.authenticator.EasySSLSocketFactory;
-import eu.alefzero.webdav.HttpMkCol;
-
-import android.net.Uri;
-import android.util.Log;
-
-public class WebdavClient {
-  private DefaultHttpClient mHttpClient;
-  private BasicHttpContext mHttpContext;
-  private HttpHost mTargetHost;
-  private SchemeRegistry mSchemeRegistry;
-  private Uri mUri;
-  final private static String TAG = "WebdavClient";
-  
-  WebdavClient(Uri uri) {
-    mUri = uri;
-    mSchemeRegistry = new SchemeRegistry();
-    setupHttpClient();
-  }
-  
-  void setCredentials(String username, String password) {
-    // determine default port for http or https
-    int targetPort = mTargetHost.getPort() == -1 ? 
-                        ( mUri.getScheme().equals("https") ? 443 : 80)
-                        : mUri.getPort();
-
-    mHttpClient.getCredentialsProvider().setCredentials(
-        new AuthScope(mUri.getHost(), targetPort), 
-        new UsernamePasswordCredentials(username, password));
-    BasicScheme basicAuth = new BasicScheme();
-    mHttpContext.setAttribute("preemptive-auth", basicAuth);
-  }
-  
-  void allowUnsignedCertificates() {
-    // https
-    mSchemeRegistry.register(new Scheme("https", new EasySSLSocketFactory(), 443));
-  }
-  
-  boolean downloadFile(String filepath, File targetPath) {
-    HttpGet get = new HttpGet(mUri.toString() + filepath.replace(" ", "%20"));
-    get.setHeader("Host", mUri.getHost());
-    get.setHeader("User-Agent", "Android-ownCloud");
-    
-    try {
-      HttpResponse response = mHttpClient.execute(mTargetHost, get, mHttpContext);
-      if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
-        return false;
-      }
-      BufferedInputStream bis = new BufferedInputStream(response.getEntity().getContent());
-      FileOutputStream fos = new FileOutputStream(targetPath);
-      
-      byte[] bytes = new byte[512];
-      int readResult;
-      while ((readResult = bis.read(bytes)) != -1) fos.write(bytes, 0, readResult);
-      
-    } catch (IOException e) {
-      e.printStackTrace();
-      return false;
-    }
-    return true;
-  }
-  
-  void getFileList(String dirPath) {
-    
-  }
-  
-  boolean putFile(String localFile,
-                  String remoteTarget,
-                  String contentType) {
-    boolean result = true;
-    HttpPut method = new HttpPut(mUri.toString() + remoteTarget.replace(" ", "%20"));
-    method.setHeader("Content-type", contentType);
-    method.setHeader("Host", mUri.getHost());
-    method.setHeader("User-Agent", "Android-ownCloud");
-
-    try {
-      FileBody fb = new FileBody(new File(localFile, contentType));
-      final FileEntity fileEntity = new FileEntity(new File(localFile), contentType);
-
-      method.setEntity(fileEntity);
-      Log.i(TAG, "executing:" + method.getRequestLine().toString());
-
-      mHttpClient.execute(mTargetHost, method, mHttpContext);
-      /*mHandler.post(new Runnable() {
-      public void run() {
-        Uploader.this.PartialupdateUpload(c.getString(c.getColumnIndex(Media.DATA)),
-                                                  c.getString(c.getColumnIndex(Media.DISPLAY_NAME)),
-                                                  mUploadPath + (mUploadPath.equals("/")?"":"/"),
-                                                  fileEntity.getContentType().getValue(),
-                                                  fileEntity.getContentLength()+"");
-      }
-    });
-    Log.i(TAG, "Uploading, done");
-*/
-      Log.i(TAG, "Uploading, done");
-    } catch (final Exception e) {
-      Log.i(TAG, ""+e.getMessage());
-      result = false;
-    }
-    
-    return result;
-  }
-  
-  public boolean createDirectory(String path) {
-    HttpMkCol method = new HttpMkCol(mUri.toString() + path + "/");
-    method.setHeader("User-Agent", "Android-ownCloud");
-    
-    try {
-      mHttpClient.execute(mTargetHost, method, mHttpContext);
-      Log.i(TAG, "Creating dir completed");
-    } catch (final Exception e) {
-      e.printStackTrace();
-      return false;
-    }
-    return true;
-  }
-  
-  private void setupHttpClient() {
-    // http scheme
-    mSchemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
-    mSchemeRegistry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
-    
-    HttpParams params = new BasicHttpParams();
-    params.setParameter(ConnManagerPNames.MAX_TOTAL_CONNECTIONS, 30);
-    params.setParameter(ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE, new ConnPerRouteBean(30));
-    params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, false);
-    HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
-
-    mHttpContext = new BasicHttpContext();
-    ClientConnectionManager cm = new ThreadSafeClientConnManager(params, mSchemeRegistry);
-
-    int port = mUri.getPort() == -1 ? 
-                 mUri.getScheme().equals("https") ? 443 : 80
-               : mUri.getPort();
-    
-    mTargetHost = new HttpHost(mUri.getHost(), port, mUri.getScheme());
-    
-    mHttpClient = new DefaultHttpClient(cm, params);
-  }
-}
+/* ownCloud Android client application
+ *   Copyright (C) 2011  Bartek Przybylski
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package eu.alefzero.webdav;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+
+import org.apache.http.HttpHost;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.HttpVersion;
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.UsernamePasswordCredentials;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPut;
+import org.apache.http.conn.ClientConnectionManager;
+import org.apache.http.conn.params.ConnManagerPNames;
+import org.apache.http.conn.params.ConnPerRouteBean;
+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.FileEntity;
+import org.apache.http.entity.mime.content.FileBody;
+import org.apache.http.impl.auth.BasicScheme;
+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.BasicHttpContext;
+
+import eu.alefzero.owncloud.authenticator.EasySSLSocketFactory;
+
+import android.net.Uri;
+import android.util.Log;
+
+/**
+ * A basic WebDAV-Client
+ * @author Bartek Przybylski
+ *
+ */
+public class WebdavClient {
+  private DefaultHttpClient mHttpClient;
+  private BasicHttpContext mHttpContext;
+  private HttpHost mTargetHost;
+  private SchemeRegistry mSchemeRegistry;
+  private Uri mUri;
+  final private static String TAG = "WebdavClient";
+  
+  public WebdavClient(Uri uri) {
+    mUri = uri;
+    mSchemeRegistry = new SchemeRegistry();
+    setupHttpClient();
+  }
+  
+  public void setCredentials(String username, String password) {
+    // determine default port for http or https
+    int targetPort = mTargetHost.getPort() == -1 ? 
+                        ( mUri.getScheme().equals("https") ? 443 : 80)
+                        : mUri.getPort();
+
+    mHttpClient.getCredentialsProvider().setCredentials(
+        new AuthScope(mUri.getHost(), targetPort), 
+        new UsernamePasswordCredentials(username, password));
+    BasicScheme basicAuth = new BasicScheme();
+    mHttpContext.setAttribute("preemptive-auth", basicAuth);
+  }
+  
+  public void allowUnsignedCertificates() {
+    // https
+    mSchemeRegistry.register(new Scheme("https", new EasySSLSocketFactory(), 443));
+  }
+  
+  public boolean downloadFile(String filepath, File targetPath) {
+    HttpGet get = new HttpGet(mUri.toString() + filepath.replace(" ", "%20"));
+    get.setHeader("Host", mUri.getHost());
+    get.setHeader("User-Agent", "Android-ownCloud");
+    
+    try {
+      HttpResponse response = mHttpClient.execute(mTargetHost, get, mHttpContext);
+      if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
+        return false;
+      }
+      BufferedInputStream bis = new BufferedInputStream(response.getEntity().getContent());
+      FileOutputStream fos = new FileOutputStream(targetPath);
+      
+      byte[] bytes = new byte[512];
+      int readResult;
+      while ((readResult = bis.read(bytes)) != -1) fos.write(bytes, 0, readResult);
+      
+    } catch (IOException e) {
+      e.printStackTrace();
+      return false;
+    }
+    return true;
+  }
+  
+  void getFileList(String dirPath) {
+    
+  }
+  
+  public boolean putFile(String localFile,
+                  String remoteTarget,
+                  String contentType) {
+    boolean result = true;
+    HttpPut method = new HttpPut(mUri.toString() + remoteTarget.replace(" ", "%20"));
+    method.setHeader("Content-type", contentType);
+    method.setHeader("Host", mUri.getHost());
+    method.setHeader("User-Agent", "Android-ownCloud");
+
+    try {
+      FileBody fb = new FileBody(new File(localFile, contentType));
+      final FileEntity fileEntity = new FileEntity(new File(localFile), contentType);
+
+      method.setEntity(fileEntity);
+      Log.i(TAG, "executing:" + method.getRequestLine().toString());
+
+      mHttpClient.execute(mTargetHost, method, mHttpContext);
+      /*mHandler.post(new Runnable() {
+      public void run() {
+        Uploader.this.PartialupdateUpload(c.getString(c.getColumnIndex(Media.DATA)),
+                                                  c.getString(c.getColumnIndex(Media.DISPLAY_NAME)),
+                                                  mUploadPath + (mUploadPath.equals("/")?"":"/"),
+                                                  fileEntity.getContentType().getValue(),
+                                                  fileEntity.getContentLength()+"");
+      }
+    });
+    Log.i(TAG, "Uploading, done");
+*/
+      Log.i(TAG, "Uploading, done");
+    } catch (final Exception e) {
+      Log.i(TAG, ""+e.getMessage());
+      result = false;
+    }
+    
+    return result;
+  }
+  
+  public boolean createDirectory(String path) {
+    HttpMkCol method = new HttpMkCol(mUri.toString() + path + "/");
+    method.setHeader("User-Agent", "Android-ownCloud");
+    
+    try {
+      mHttpClient.execute(mTargetHost, method, mHttpContext);
+      Log.i(TAG, "Creating dir completed");
+    } catch (final Exception e) {
+      e.printStackTrace();
+      return false;
+    }
+    return true;
+  }
+  
+  private void setupHttpClient() {
+    // http scheme
+    mSchemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
+    mSchemeRegistry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
+    
+    HttpParams params = new BasicHttpParams();
+    params.setParameter(ConnManagerPNames.MAX_TOTAL_CONNECTIONS, 30);
+    params.setParameter(ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE, new ConnPerRouteBean(30));
+    params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, false);
+    HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
+
+    mHttpContext = new BasicHttpContext();
+    ClientConnectionManager cm = new ThreadSafeClientConnManager(params, mSchemeRegistry);
+
+    int port = mUri.getPort() == -1 ? 
+                 mUri.getScheme().equals("https") ? 443 : 80
+               : mUri.getPort();
+    
+    mTargetHost = new HttpHost(mUri.getHost(), port, mUri.getScheme());
+    
+    mHttpClient = new DefaultHttpClient(cm, params);
+  }
+}