浏览代码

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 年之前
父节点
当前提交
dc8c32fb3f
共有 36 个文件被更改,包括 3651 次插入3161 次删除
  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);
+  }
+}