Merge branch 'develop' into oauth_login
authorDavid A. Velasco <dvelasco@solidgear.es>
Fri, 3 May 2013 08:24:20 +0000 (10:24 +0200)
committerDavid A. Velasco <dvelasco@solidgear.es>
Fri, 3 May 2013 08:24:20 +0000 (10:24 +0200)
Conflicts:
res/layout-land/account_setup.xml
res/layout/account_setup.xml

77 files changed:
AndroidManifest.xml
res/layout-land/account_setup.xml
res/layout/account_setup.xml
res/values/oauth2_configuration.xml [new file with mode: 0644]
res/values/strings.xml
res/values/styles.xml
src/com/owncloud/android/AccountUtils.java
src/com/owncloud/android/DisplayUtils.java
src/com/owncloud/android/Uploader.java
src/com/owncloud/android/authentication/AccountAuthenticator.java [new file with mode: 0644]
src/com/owncloud/android/authentication/AccountAuthenticatorService.java [new file with mode: 0644]
src/com/owncloud/android/authentication/AuthenticatorActivity.java [new file with mode: 0644]
src/com/owncloud/android/authentication/OAuth2Constants.java [new file with mode: 0644]
src/com/owncloud/android/authenticator/AccountAuthenticator.java [deleted file]
src/com/owncloud/android/authenticator/AccountAuthenticatorService.java [deleted file]
src/com/owncloud/android/authenticator/AuthenticationRunnable.java [deleted file]
src/com/owncloud/android/authenticator/OnAuthenticationResultListener.java [deleted file]
src/com/owncloud/android/authenticator/OnConnectCheckListener.java [deleted file]
src/com/owncloud/android/datamodel/FileDataStorageManager.java
src/com/owncloud/android/db/DbHandler.java
src/com/owncloud/android/extensions/ExtensionsAvailableDialog.java
src/com/owncloud/android/extensions/ExtensionsListActivity.java
src/com/owncloud/android/files/BootupBroadcastReceiver.java
src/com/owncloud/android/files/InstantUploadBroadcastReceiver.java
src/com/owncloud/android/files/OwnCloudFileObserver.java
src/com/owncloud/android/files/services/FileDownloader.java
src/com/owncloud/android/files/services/FileObserverService.java
src/com/owncloud/android/files/services/FileOperation.java [deleted file]
src/com/owncloud/android/files/services/FileUploader.java
src/com/owncloud/android/location/LocationServiceLauncherReciever.java
src/com/owncloud/android/location/LocationUpdateService.java
src/com/owncloud/android/network/AdvancedSslSocketFactory.java
src/com/owncloud/android/network/AdvancedX509TrustManager.java
src/com/owncloud/android/network/BearerAuthScheme.java [new file with mode: 0644]
src/com/owncloud/android/network/BearerCredentials.java [new file with mode: 0644]
src/com/owncloud/android/network/OwnCloudClientUtils.java
src/com/owncloud/android/operations/ChunkedUploadFileOperation.java
src/com/owncloud/android/operations/ConnectionCheckOperation.java [deleted file]
src/com/owncloud/android/operations/CreateFolderOperation.java [new file with mode: 0644]
src/com/owncloud/android/operations/DownloadFileOperation.java
src/com/owncloud/android/operations/ExistenceCheckOperation.java [new file with mode: 0644]
src/com/owncloud/android/operations/OAuth2GetAccessToken.java [new file with mode: 0644]
src/com/owncloud/android/operations/OwnCloudServerCheckOperation.java [new file with mode: 0644]
src/com/owncloud/android/operations/RemoteOperation.java
src/com/owncloud/android/operations/RemoteOperationResult.java
src/com/owncloud/android/operations/RemoveFileOperation.java
src/com/owncloud/android/operations/RenameFileOperation.java
src/com/owncloud/android/operations/SynchronizeFileOperation.java
src/com/owncloud/android/operations/SynchronizeFolderOperation.java
src/com/owncloud/android/operations/UpdateOCVersionOperation.java
src/com/owncloud/android/providers/FileContentProvider.java
src/com/owncloud/android/syncadapter/AbstractOwnCloudSyncAdapter.java
src/com/owncloud/android/syncadapter/ContactSyncAdapter.java
src/com/owncloud/android/syncadapter/FileSyncAdapter.java
src/com/owncloud/android/ui/activity/AccountSelectActivity.java
src/com/owncloud/android/ui/activity/AuthenticatorActivity.java [deleted file]
src/com/owncloud/android/ui/activity/ErrorsWhileCopyingHandlerActivity.java
src/com/owncloud/android/ui/activity/FailedUploadActivity.java
src/com/owncloud/android/ui/activity/FileDetailActivity.java
src/com/owncloud/android/ui/activity/FileDisplayActivity.java
src/com/owncloud/android/ui/activity/InstantUploadActivity.java
src/com/owncloud/android/ui/activity/LandingActivity.java
src/com/owncloud/android/ui/activity/UploadFilesActivity.java
src/com/owncloud/android/ui/dialog/SslValidatorDialog.java
src/com/owncloud/android/ui/fragment/ConfirmationDialogFragment.java
src/com/owncloud/android/ui/fragment/FileDetailFragment.java
src/com/owncloud/android/ui/fragment/LocalFileListFragment.java
src/com/owncloud/android/ui/fragment/OCFileListFragment.java
src/com/owncloud/android/ui/preview/FileDownloadFragment.java
src/com/owncloud/android/ui/preview/PreviewImageActivity.java
src/com/owncloud/android/ui/preview/PreviewImageFragment.java
src/com/owncloud/android/ui/preview/PreviewImagePagerAdapter.java
src/com/owncloud/android/ui/preview/PreviewMediaFragment.java
src/com/owncloud/android/ui/preview/PreviewVideoActivity.java
src/com/owncloud/android/utils/FileStorageUtils.java
src/eu/alefzero/webdav/WebdavClient.java
src/eu/alefzero/webdav/WebdavEntry.java

index 421880f..ba32f6c 100644 (file)
@@ -90,7 +90,7 @@
         <activity android:name=".ui.activity.PreferencesNewSessionewSession" >
         </activity>
         
-               <activity       android:name="com.owncloud.android.ui.preview.PreviewImageActivity" />
+        <activity      android:name="com.owncloud.android.ui.preview.PreviewImageActivity" />
                        
         <activity      android:name="com.owncloud.android.ui.preview.PreviewVideoActivity"
                                        android:label="@string/app_name"
@@ -98,7 +98,7 @@
                </activity>        
 
         <service
-            android:name=".authenticator.AccountAuthenticatorService"
+            android:name=".authentication.AccountAuthenticatorService"
             android:exported="true">
             <intent-filter  android:priority="100">
                 <action android:name="android.accounts.AccountAuthenticator" />
         </provider>
 
         <activity
-            android:name=".ui.activity.AuthenticatorActivity"
+            android:name=".authentication.AuthenticatorActivity"
             android:exported="true"
-            android:theme="@style/Theme.ownCloud.noActionBar" >
+            android:theme="@style/Theme.ownCloud.noActionBar" 
+            android:launchMode="singleTask">
+            <intent-filter>
+                <action android:name="android.intent.action.VIEW" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.BROWSABLE" />
+                <data android:scheme="@string/oauth2_redirect_scheme" />
+            </intent-filter>
             <intent-filter>
                 <action android:name="com.owncloud.android.workaround.accounts.CREATE" />
                 <category android:name="android.intent.category.DEFAULT" />
         
         <activity android:name=".ui.activity.LogHistoryActivity"/>
         
-        <receiver android:name=".files.InstantUploadBroadcastReceiver">
-            <intent-filter>
-                <action android:name="com.android.camera.NEW_PICTURE" />
-                <data android:mimeType="image/*" />
+        <receiver android:name=".files.InstantUploadBroadcastReceiver">\r
+            <intent-filter>\r
+                <action android:name="com.android.camera.NEW_PICTURE" />\r
+                <data android:mimeType="image/*" />\r
             </intent-filter>
             <intent-filter>
                 <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
-            </intent-filter>
-        </receiver>
-        <receiver android:name=".files.BootupBroadcastReceiver">
-            <intent-filter>
-                <action android:name="android.intent.action.BOOT_COMPLETED"/>
-            </intent-filter>
-        </receiver>
-        <service android:name=".files.services.FileObserverService"/>
-    </application>
-    
+            </intent-filter>\r
+        </receiver>\r
+        <receiver android:name=".files.BootupBroadcastReceiver">\r
+            <intent-filter>\r
+                <action android:name="android.intent.action.BOOT_COMPLETED"/>\r
+            </intent-filter>\r
+        </receiver>\r
+        <service android:name=".files.services.FileObserverService"/>\r
+        \r
+    </application>\r
+\r
 </manifest>
index e694e9e..ce78ace 100644 (file)
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ownCloud Android client application
-
-  Copyright (C) 2012  Bartek Przybylski
-  Copyright (C) 2012-2013 ownCloud Inc.
-
-  This program is free software: you can redistribute it and/or modify
-  it under the terms of the GNU General Public License version 2,
-  as published by the Free Software Foundation.
-
-  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/>.
--->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:oc="http://schemas.android.com/apk/res/com.owncloud.android"
-    android:layout_width="fill_parent"
-    android:layout_height="fill_parent"
-    android:focusable="true"
-    android:gravity="center|fill"
-    android:orientation="vertical" >
-
-    <FrameLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center"
-        android:layout_marginLeft="16dip"
-        android:layout_marginRight="16dip"
-        android:layout_weight="1" >
-
-        <LinearLayout
-            android:layout_width="match_parent"
-            android:layout_height="match_parent" >
-
-            <ImageView
-                android:id="@+id/imageView1"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:layout_margin="7dp"
-                android:layout_weight="1"
-                android:src="@drawable/owncloud_logo" />
-
-            <LinearLayout
-                android:id="@+id/LinearLayout1"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_gravity="center"
-                android:layout_weight="1"
-                android:orientation="vertical" >
-
-                <FrameLayout
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:layout_weight="1" >
-
-                    <EditText
-                        android:id="@+id/host_URL"
-                        android:layout_width="match_parent"
-                        android:layout_height="wrap_content"
-                        android:layout_weight="1"
-                        android:ems="10"
-                        android:hint="@string/auth_host_url"
-                        android:inputType="textNoSuggestions">
-                        <requestFocus />
-                    </EditText>
-
-                    <ImageView
-                        android:id="@+id/refreshButton"
-                        android:layout_width="wrap_content"
-                        android:layout_height="wrap_content"
-                        android:layout_gravity="right|center_vertical"
-                        android:src="@drawable/ic_action_refresh_black"
-                        android:visibility="invisible" />
-                </FrameLayout>
-
-                <LinearLayout
-                    android:layout_width="match_parent"
-                    android:layout_height="50dp"
-                    android:layout_weight="1" >
-
-                    <ImageView
-                        android:id="@+id/action_indicator"
-                        android:layout_width="wrap_content"
-                        android:layout_height="wrap_content"
-                        android:layout_marginLeft="5dp"
-                        android:layout_marginRight="5dp"
-                        android:src="@android:drawable/stat_notify_sync"
-                        android:visibility="invisible" />
-
-                    <TextView
-                        android:id="@+id/status_text"
-                        android:layout_width="wrap_content"
-                        android:layout_height="wrap_content"
-                        android:text="TextView"
-                        android:visibility="invisible" />
-                </LinearLayout>
-
-                <TextView
-                    android:id="@+id/textView2"
-                    android:layout_width="wrap_content"
-                    android:layout_height="0dp"
-                    android:layout_weight="1"
-                    android:text="@string/auth_login_details"
-                    android:textAppearance="?android:attr/textAppearanceSmall" />
-
-                <EditText
-                    android:id="@+id/account_username"
-                    android:layout_width="match_parent"
-                    android:layout_height="0dp"
-                    android:layout_weight="1"
-                    android:ems="10"
-                    android:hint="@string/auth_username"
-                    android:inputType="textNoSuggestions" />
-
-                <FrameLayout
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:layout_weight="1" >
-
-                    <EditText
-                        android:id="@+id/account_password"
-                        android:layout_width="match_parent"
-                        android:layout_height="wrap_content"
-                        android:layout_weight="1"
-                        android:ems="10"
-                        android:hint="@string/auth_password"
-                        android:inputType="textPassword"/>
-
-                    <ImageView
-                        android:id="@+id/viewPassword"
-                        android:layout_width="wrap_content"
-                        android:layout_height="wrap_content"
-                        android:layout_gravity="right|center_vertical"
-                        android:src="@android:drawable/ic_menu_view"
-                        android:visibility="invisible" />
-                </FrameLayout>
-            </LinearLayout>
-        </LinearLayout>
-    </FrameLayout>
-
-    <RelativeLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_alignParentBottom="true" >
-
-        <LinearLayout
-            android:id="@+id/buttons_layout"        
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:weightSum="1">
-
-            <Button
-                android:id="@+id/buttonOK"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_weight=".5"
-                android:layout_marginLeft="16dip"
-                       android:layout_marginRight="16dip"
-                android:enabled="false"
-                android:onClick="onOkClick"
-                android:text="@string/setup_btn_connect"
-                android:textColor="@android:color/black" />
-            
-        </LinearLayout>
-        
-               <Button
-                       android:id="@+id/account_register"
-                       android:layout_width="wrap_content"
-                       android:layout_height="wrap_content"
-                       android:layout_below="@id/buttons_layout"
-                       android:layout_centerHorizontal="true"
-                       android:onClick="onRegisterClick"
-                       android:paddingTop="10dp"
-                       android:paddingBottom="10dp"
-                       android:textColor="#0000FF"
-                       android:background="@android:color/transparent" />
-                       <!-- android:text="@string/app_name @string/auth_register" /-->
-        
-    </RelativeLayout>
-
-</LinearLayout>
+<?xml version="1.0" encoding="utf-8"?>\r
+<!--\r
+  ownCloud Android client application\r
+\r
+  Copyright (C) 2012  Bartek Przybylski\r
+  Copyright (C) 2012-2013 ownCloud Inc.\r
+\r
+  This program is free software: you can redistribute it and/or modify\r
+  it under the terms of the GNU General Public License version 2,\r
+  as published by the Free Software Foundation.\r
+\r
+  This program is distributed in the hope that it will be useful,\r
+  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+  GNU General Public License for more details.\r
+\r
+  You should have received a copy of the GNU General Public License\r
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.\r
+-->\r
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"\r
+    xmlns:oc="http://schemas.android.com/apk/res/com.owncloud.android"\r
+    android:layout_width="fill_parent"\r
+    android:layout_height="fill_parent"\r
+    android:focusable="true"\r
+    android:gravity="center|fill"\r
+    android:orientation="vertical" >\r
+\r
+    <FrameLayout\r
+        android:layout_width="match_parent"\r
+        android:layout_height="wrap_content"\r
+        android:layout_gravity="center"\r
+        android:layout_marginLeft="16dip"\r
+        android:layout_marginRight="16dip"\r
+        android:layout_weight="1" >\r
+\r
+        <LinearLayout\r
+            android:layout_width="match_parent"\r
+            android:layout_height="match_parent" >\r
+\r
+            <ImageView\r
+                android:id="@+id/imageView1"\r
+                android:layout_width="match_parent"\r
+                android:layout_height="match_parent"\r
+                android:layout_margin="7dp"\r
+                android:layout_weight="1"\r
+                android:src="@drawable/owncloud_logo" />\r
+\r
+            <LinearLayout\r
+                android:id="@+id/LinearLayout1"\r
+                android:layout_width="match_parent"\r
+                android:layout_height="wrap_content"\r
+                android:layout_gravity="center"\r
+                android:layout_weight="1"\r
+                android:orientation="vertical" >\r
+\r
+                <FrameLayout\r
+                    android:layout_width="match_parent"\r
+                    android:layout_height="wrap_content"\r
+                    android:layout_weight="1" >\r
+\r
+                    <EditText\r
+                        android:id="@+id/hostUrlInput"\r
+                        android:layout_width="match_parent"\r
+                        android:layout_height="wrap_content"\r
+                        android:ems="10"\r
+                        android:hint="@string/auth_host_url"\r
+                        android:inputType="textNoSuggestions">\r
+                        <requestFocus />\r
+                    </EditText>\r
+\r
+                    <ImageView\r
+                        android:id="@+id/refreshButton"\r
+                        android:layout_width="wrap_content"\r
+                        android:layout_height="wrap_content"\r
+                        android:layout_gravity="right|center_vertical"\r
+                        android:src="@drawable/ic_action_refresh_black"\r
+                       android:onClick="onRefreshClick"\r
+                        android:visibility="invisible" />\r
+                </FrameLayout>\r
+\r
+                <LinearLayout\r
+                    android:layout_width="match_parent"\r
+                    android:layout_height="50dp"\r
+                    android:layout_weight="1" >\r
+\r
+                    <ImageView\r
+                        android:id="@+id/action_indicator"\r
+                        android:layout_width="wrap_content"\r
+                        android:layout_height="wrap_content"\r
+                        android:layout_marginLeft="5dp"\r
+                        android:layout_marginRight="5dp"\r
+                        android:src="@android:drawable/stat_notify_sync"\r
+                        android:visibility="invisible" />\r
+\r
+                    <TextView\r
+                        android:id="@+id/status_text"\r
+                        android:layout_width="wrap_content"\r
+                        android:layout_height="wrap_content"\r
+                        android:text="TextView"\r
+                        android:visibility="invisible" />\r
+                </LinearLayout>\r
+\r
+                <CheckBox\r
+                    android:id="@+id/oauth_onOff_check"\r
+                    android:layout_width="wrap_content"\r
+                    android:layout_height="wrap_content"\r
+                    android:checked="false"\r
+                    android:onClick="onCheckClick"\r
+                    android:text="@string/oauth_check_onoff"\r
+                    android:textAppearance="?android:attr/textAppearanceSmall" />\r
+\r
+                <TextView\r
+                    android:id="@+id/textView2"\r
+                    android:layout_width="wrap_content"\r
+                    android:layout_height="0dp"\r
+                    android:layout_weight="1"\r
+                    android:text="@string/auth_login_details"\r
+                    android:textAppearance="?android:attr/textAppearanceSmall" />\r
+\r
+                   <EditText\r
+                       android:id="@+id/oAuthEntryPoint_1"\r
+                       android:layout_width="match_parent"\r
+                       android:layout_height="wrap_content"\r
+                       android:layout_weight="1"\r
+                       android:ems="10"\r
+                       android:enabled="false"\r
+                       android:text="@string/oauth2_url_endpoint_auth"\r
+                       android:singleLine="true"\r
+                       android:visibility="gone" >\r
+       \r
+                       <requestFocus />\r
+                   </EditText>            \r
+       \r
+                   <EditText\r
+                       android:id="@+id/oAuthEntryPoint_2"\r
+                       android:layout_width="match_parent"\r
+                       android:layout_height="wrap_content"\r
+                       android:layout_weight="1"\r
+                       android:ems="10"\r
+                       android:enabled="false"\r
+                       android:text="@string/oauth2_url_endpoint_access"\r
+                       android:singleLine="true"\r
+                       android:visibility="gone" >\r
+       \r
+                       <requestFocus />\r
+                   </EditText>            \r
+       \r
+                <EditText\r
+                    android:id="@+id/account_username"\r
+                    android:layout_width="match_parent"\r
+                    android:layout_height="0dp"\r
+                    android:layout_weight="1"\r
+                    android:ems="10"\r
+                    android:hint="@string/auth_username"\r
+                    android:inputType="textNoSuggestions" />\r
+\r
+                <FrameLayout\r
+                    android:layout_width="match_parent"\r
+                    android:layout_height="wrap_content"\r
+                    android:layout_weight="1" >\r
+\r
+                    <EditText\r
+                        android:id="@+id/account_password"\r
+                        android:layout_width="match_parent"\r
+                        android:layout_height="wrap_content"\r
+                        android:ems="10"\r
+                        android:hint="@string/auth_password"\r
+                        android:inputType="textPassword"/>\r
+\r
+                    <ImageView\r
+                        android:id="@+id/viewPasswordButton"\r
+                        android:layout_width="wrap_content"\r
+                        android:layout_height="wrap_content"\r
+                        android:layout_gravity="right|center_vertical"\r
+                        android:src="@android:drawable/ic_menu_view"\r
+                                               android:onClick="onViewPasswordClick"\r
+                        android:visibility="invisible" />\r
+                </FrameLayout>\r
+                \r
+                   <TextView\r
+                       android:id="@+id/auth_status_text"\r
+                       android:layout_width="match_parent"\r
+                       android:layout_height="wrap_content"\r
+                       android:layout_weight="1" \r
+                       android:text="@string/text_placeholder"\r
+                       android:layout_marginLeft="5dp"\r
+                       android:layout_marginRight="5dp"\r
+                                       android:drawableLeft="@android:drawable/stat_notify_sync"\r
+                               android:drawablePadding="5dip"\r
+                               android:visibility="invisible"                \r
+                       />\r
+                \r
+            </LinearLayout>\r
+            \r
+        </LinearLayout>\r
+    </FrameLayout>\r
+\r
+    <RelativeLayout\r
+        android:layout_width="match_parent"\r
+        android:layout_height="wrap_content"\r
+        android:layout_alignParentBottom="true" >\r
+\r
+        <LinearLayout\r
+            android:id="@+id/buttons_layout"        \r
+            android:layout_width="match_parent"\r
+            android:layout_height="wrap_content"\r
+            android:weightSum="1">\r
+\r
+            <Button\r
+                android:id="@+id/buttonOK"\r
+                android:layout_width="match_parent"\r
+                android:layout_height="wrap_content"\r
+                android:layout_weight=".5"\r
+                android:layout_marginLeft="16dip"\r
+                       android:layout_marginRight="16dip"\r
+                android:enabled="false"\r
+                android:onClick="onOkClick"\r
+                android:text="@string/setup_btn_connect"\r
+                android:textColor="@android:color/black" />\r
+            \r
+        </LinearLayout>\r
+        \r
+               <Button\r
+                       android:id="@+id/account_register"\r
+                       android:layout_width="wrap_content"\r
+                       android:layout_height="wrap_content"\r
+                       android:layout_below="@id/buttons_layout"\r
+                       android:layout_centerHorizontal="true"\r
+                       android:onClick="onRegisterClick"\r
+                       android:paddingTop="10dp"\r
+                       android:paddingBottom="10dp"\r
+                       android:textColor="#0000FF"\r
+                       android:background="@android:color/transparent" />\r
+                       <!-- android:text="@string/app_name @string/auth_register" /-->\r
+        \r
+    </RelativeLayout>\r
+\r
+</LinearLayout>\r
index 1cfc49d..eee08c1 100644 (file)
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ownCloud Android client application
-
-  Copyright (C) 2012  Bartek Przybylski
-  Copyright (C) 2012-2013 ownCloud Inc.
-
-  This program is free software: you can redistribute it and/or modify
-  it under the terms of the GNU General Public License version 2,
-  as published by the Free Software Foundation.
-
-  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/>.
--->
-<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="fill_parent"
-    android:layout_height="fill_parent"
-    android:orientation="vertical">
-    
-       <LinearLayout
-           android:layout_width="fill_parent"
-           android:layout_height="wrap_content"
-           android:layout_gravity="center"
-           android:focusable="true"
-           android:gravity="center"
-           android:orientation="vertical" >
-           
-           <FrameLayout
-               android:layout_width="match_parent"
-               android:layout_height="0dip"
-               android:layout_gravity="center"
-               android:layout_marginBottom="50dip"
-               android:layout_marginLeft="16dip"
-               android:layout_marginRight="16dip"
-               android:layout_weight="1" >
-       
-               <LinearLayout
-                   android:id="@+id/LinearLayout1"
-                   android:layout_width="match_parent"
-                   android:layout_height="wrap_content"
-                   android:layout_gravity="center"
-                   android:orientation="vertical" >
-       
-                   <ImageView
-                       android:id="@+id/imageView1"
-                       android:layout_width="match_parent"
-                       android:layout_height="wrap_content"
-                       android:layout_marginBottom="10dp"
-                       android:layout_weight="1"
-                       android:src="@drawable/owncloud_logo" />
-       
-                   <FrameLayout
-                       android:layout_width="match_parent"
-                       android:layout_height="wrap_content"
-                       android:layout_weight="1" >
-       
-                       <EditText
-                           android:id="@+id/host_URL"
-                           android:layout_width="match_parent"
-                           android:layout_height="wrap_content"
-                           android:ems="10"
-                           android:hint="@string/auth_host_url"
-                           android:inputType="textNoSuggestions" >
-                           <requestFocus />
-                       </EditText>
-       
-                       <ImageView
-                           android:id="@+id/refreshButton"
-                           android:layout_width="wrap_content"
-                           android:layout_height="wrap_content"
-                           android:src="@drawable/ic_action_refresh_black"
-                           android:layout_gravity="right|center_vertical"
-                           android:visibility="invisible" />
-       
-                   </FrameLayout>
-       
-                   <LinearLayout
-                       android:layout_width="match_parent"
-                       android:layout_height="50dp"
-                       android:layout_weight="1" >
-       
-                       <ImageView
-                           android:id="@+id/action_indicator"
-                           android:layout_width="wrap_content"
-                           android:layout_height="wrap_content"
-                           android:layout_marginLeft="5dp"
-                           android:layout_marginRight="5dp"
-                           android:src="@android:drawable/stat_notify_sync"
-                           android:visibility="invisible" />
-       
-                       <TextView
-                           android:id="@+id/status_text"
-                           android:layout_width="wrap_content"
-                           android:layout_height="wrap_content"
-                           android:text="TextView"
-                           android:visibility="invisible" />
-       
-                   </LinearLayout>
-       
-                   <TextView
-                       android:id="@+id/textView2"
-                       android:layout_width="wrap_content"
-                       android:layout_height="0dp"
-                       android:layout_weight="1"
-                       android:text="@string/auth_login_details"
-                       android:textAppearance="?android:attr/textAppearanceSmall" />
-       
-                   <EditText
-                       android:id="@+id/account_username"
-                       android:layout_width="match_parent"
-                       android:layout_height="0dp"
-                       android:layout_weight="1"
-                       android:ems="10"
-                       android:hint="@string/auth_username"
-                       android:inputType="textNoSuggestions" />
-       
-                   <FrameLayout
-                       android:layout_width="match_parent"
-                       android:layout_height="wrap_content"
-                       android:layout_weight="1" >
-       
-                       <EditText
-                           android:id="@+id/account_password"
-                           android:layout_width="match_parent"
-                           android:layout_height="wrap_content"
-                           android:ems="10"
-                           android:hint="@string/auth_password"
-                           android:inputType="textPassword"/>
-       
-                       <ImageView
-                           android:id="@+id/viewPassword"
-                           android:layout_width="wrap_content"
-                           android:layout_height="wrap_content"
-                           android:layout_gravity="right|center_vertical"
-                           android:src="@android:drawable/ic_menu_view"
-                           android:visibility="invisible" />
-       
-                   </FrameLayout>
-       
-                   </LinearLayout>
-       
-           </FrameLayout>
-       
-           <RelativeLayout
-               android:layout_width="match_parent"
-               android:layout_height="wrap_content">
-       
-               <LinearLayout
-                   android:id="@+id/buttons_layout"
-                   android:layout_width="fill_parent"
-                   android:layout_height="wrap_content"
-                   android:weightSum="1">
-       
-                   <Button
-                       android:id="@+id/buttonOK"
-                       android:layout_width="match_parent"
-                       android:layout_height="wrap_content"
-                           android:layout_gravity="center_horizontal"
-                               android:layout_marginLeft="16dip"
-                           android:layout_marginRight="16dip"
-                       android:enabled="false"
-                       android:onClick="onOkClick"
-                       android:text="@string/setup_btn_connect"
-                       android:textColor="@android:color/black" />
-       
-               </LinearLayout>
-               
-                       <Button
-                               android:id="@+id/account_register"
-                               android:layout_width="wrap_content"
-                               android:layout_height="wrap_content"
-                               android:layout_below="@id/buttons_layout"
-                               android:layout_centerHorizontal="true"
-                               android:onClick="onRegisterClick"
-                               android:paddingTop="10dp"
-                               android:paddingBottom="10dp"
-                               android:textColor="#0000FF"
-                               android:background="@android:color/transparent" />
-               
-           </RelativeLayout>
-           
-       </LinearLayout>
-       
-</ScrollView>
\ No newline at end of file
+<?xml version="1.0" encoding="utf-8"?>\r
+<!--\r
+  ownCloud Android client application\r
+\r
+  Copyright (C) 2012  Bartek Przybylski\r
+  Copyright (C) 2012-2013 ownCloud Inc.\r
+\r
+  This program is free software: you can redistribute it and/or modify\r
+  it under the terms of the GNU General Public License version 2,\r
+  as published by the Free Software Foundation.\r
+\r
+  This program is distributed in the hope that it will be useful,\r
+  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+  GNU General Public License for more details.\r
+\r
+  You should have received a copy of the GNU General Public License\r
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.\r
+-->\r
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"\r
+    android:layout_width="fill_parent"\r
+    android:layout_height="fill_parent"\r
+    android:focusable="true"\r
+    android:gravity="center|fill"\r
+    android:orientation="vertical" >\r
+\r
+       <FrameLayout\r
+               android:layout_width="match_parent"\r
+               android:layout_height="0dip"\r
+               android:layout_gravity="center"\r
+               android:layout_marginBottom="50dip"\r
+               android:layout_marginLeft="16dip"\r
+               android:layout_marginRight="16dip"\r
+               android:layout_weight="1" >\r
+       \r
+               <LinearLayout\r
+                       android:id="@+id/LinearLayout1"\r
+                       android:layout_width="match_parent"\r
+                       android:layout_height="wrap_content"\r
+                       android:layout_gravity="center"\r
+                       android:orientation="vertical" >\r
+       \r
+                       <ImageView\r
+                               android:id="@+id/imageView1"\r
+                               android:layout_width="match_parent"\r
+                               android:layout_height="wrap_content"\r
+                               android:layout_marginBottom="10dp"\r
+                               android:layout_weight="1"\r
+                               android:src="@drawable/owncloud_logo" />\r
+       \r
+            <FrameLayout\r
+                android:layout_width="match_parent"\r
+                android:layout_height="wrap_content"\r
+                android:layout_weight="1" >\r
+\r
+                <EditText\r
+                    android:id="@+id/hostUrlInput"\r
+                    android:layout_width="match_parent"\r
+                    android:layout_height="wrap_content"\r
+                    android:ems="10"\r
+                    android:hint="@string/auth_host_url"\r
+                    android:inputType="textNoSuggestions" >\r
+                    <requestFocus />\r
+                </EditText>\r
+\r
+                <ImageView\r
+                    android:id="@+id/refreshButton"\r
+                    android:layout_width="wrap_content"\r
+                    android:layout_height="wrap_content"\r
+                    android:src="@drawable/ic_action_refresh_black"\r
+                    android:layout_gravity="right|center_vertical"\r
+                    android:visibility="invisible" />\r
+\r
+            </FrameLayout>\r
+\r
+            <LinearLayout\r
+                android:layout_width="match_parent"\r
+                android:layout_height="50dp"\r
+                android:layout_weight="1" >\r
+\r
+                <ImageView\r
+                    android:id="@+id/action_indicator"\r
+                    android:layout_width="wrap_content"\r
+                    android:layout_height="wrap_content"\r
+                    android:layout_marginLeft="5dp"\r
+                    android:layout_marginRight="5dp"\r
+                    android:src="@android:drawable/stat_notify_sync"\r
+                    android:visibility="invisible" />\r
+\r
+                <TextView\r
+                    android:id="@+id/status_text"\r
+                    android:layout_width="wrap_content"\r
+                    android:layout_height="wrap_content"\r
+                    android:text="TextView"\r
+                    android:visibility="invisible" />\r
+\r
+            </LinearLayout>\r
+\r
+            <CheckBox\r
+                android:id="@+id/oauth_onOff_check"\r
+                android:layout_width="wrap_content"\r
+                android:layout_height="wrap_content"\r
+                android:checked="false"\r
+                android:onClick="onCheckClick"\r
+                android:text="@string/oauth_check_onoff"\r
+                android:textAppearance="?android:attr/textAppearanceSmall" />\r
+\r
+                       <TextView\r
+                android:id="@+id/textView2"\r
+                android:layout_width="wrap_content"\r
+                android:layout_height="0dp"\r
+                android:layout_weight="1"\r
+                android:text="@string/auth_login_details"\r
+                android:textAppearance="?android:attr/textAppearanceSmall" />\r
+\r
+            <EditText\r
+                android:id="@+id/oAuthEntryPoint_1"\r
+                android:layout_width="match_parent"\r
+                android:layout_height="wrap_content"\r
+                android:layout_weight="1"\r
+                android:ems="10"\r
+                android:text="@string/oauth2_url_endpoint_auth"\r
+                android:singleLine="true"\r
+                android:visibility="gone" >\r
+\r
+                <requestFocus />\r
+            </EditText>            \r
+\r
+            <EditText\r
+                android:id="@+id/oAuthEntryPoint_2"\r
+                android:layout_width="match_parent"\r
+                android:layout_height="wrap_content"\r
+                android:layout_weight="1"\r
+                android:ems="10"\r
+                   android:text="@string/oauth2_url_endpoint_access"\r
+                android:singleLine="true"\r
+                android:visibility="gone" >\r
+\r
+                <requestFocus />\r
+            </EditText>            \r
+\r
+                       <EditText\r
+                android:id="@+id/account_username"\r
+                android:layout_width="match_parent"\r
+                android:layout_height="0dp"\r
+                android:layout_weight="1"\r
+                android:ems="10"\r
+                android:hint="@string/auth_username"\r
+                android:inputType="textNoSuggestions" />\r
+\r
+            <FrameLayout\r
+                android:layout_width="match_parent"\r
+                android:layout_height="wrap_content"\r
+                android:layout_weight="1" >\r
+\r
+                <EditText\r
+                    android:id="@+id/account_password"\r
+                    android:layout_width="match_parent"\r
+                    android:layout_height="wrap_content"\r
+                    android:ems="10"\r
+                    android:hint="@string/auth_password"\r
+                    android:inputType="textPassword"/>\r
+\r
+                <ImageView\r
+                    android:id="@+id/viewPassword"\r
+                    android:layout_width="wrap_content"\r
+                    android:layout_height="wrap_content"\r
+                    android:layout_gravity="right|center_vertical"\r
+                    android:src="@android:drawable/ic_menu_view"\r
+                                       android:onClick="onViewPasswordClick"\r
+                    android:visibility="invisible" />\r
+\r
+            </FrameLayout>\r
+       \r
+            <TextView\r
+                android:id="@+id/auth_status_text"\r
+                android:layout_width="match_parent"\r
+                android:layout_height="wrap_content"\r
+                android:layout_weight="1" \r
+                android:text="@string/text_placeholder"\r
+                android:layout_marginLeft="5dp"\r
+                android:layout_marginRight="5dp"\r
+                               android:drawableLeft="@android:drawable/stat_notify_sync"\r
+                       android:drawablePadding="5dip"\r
+                       android:visibility="invisible"                \r
+                />\r
+                    \r
+           </LinearLayout>\r
+\r
+    </FrameLayout>\r
+\r
+    <RelativeLayout\r
+        android:layout_width="match_parent"\r
+        android:layout_height="wrap_content">\r
+\r
+        <LinearLayout\r
+            android:id="@+id/buttons_layout"\r
+            android:layout_width="match_parent"\r
+            android:layout_height="wrap_content"\r
+            android:weightSum="1">\r
+\r
+            <Button\r
+                android:id="@+id/buttonOK"\r
+                android:layout_width="match_parent"\r
+                android:layout_height="wrap_content"\r
+                   android:layout_gravity="center_horizontal"\r
+                       android:layout_marginLeft="16dip"\r
+                   android:layout_marginRight="16dip"\r
+                android:enabled="false"\r
+                android:onClick="onOkClick"\r
+                android:text="@string/setup_btn_connect"\r
+                android:textColor="@android:color/black" />\r
+\r
+        </LinearLayout>\r
+        \r
+               <Button\r
+                       android:id="@+id/account_register"\r
+                       android:layout_width="wrap_content"\r
+                       android:layout_height="wrap_content"\r
+                       android:layout_below="@id/buttons_layout"\r
+                       android:layout_centerHorizontal="true"\r
+                       android:onClick="onRegisterClick"\r
+                       android:paddingTop="10dp"\r
+                       android:paddingBottom="10dp"\r
+                       android:textColor="#0000FF"\r
+                       android:background="@android:color/transparent" />\r
+               \r
+               <Button\r
+                       android:id="@+id/account_register"\r
+                       android:layout_width="wrap_content"\r
+                       android:layout_height="wrap_content"\r
+                       android:layout_below="@id/buttons_layout"\r
+                       android:layout_centerHorizontal="true"\r
+                       android:onClick="onRegisterClick"\r
+                       android:paddingTop="10dp"\r
+                       android:paddingBottom="10dp"\r
+                       android:textColor="#0000FF"\r
+                       android:background="@android:color/transparent" />\r
+                       <!-- android:text="@string/app_name @string/auth_register" /-->\r
+        \r
+    </RelativeLayout>\r
+       \r
+</ScrollView>\r
diff --git a/res/values/oauth2_configuration.xml b/res/values/oauth2_configuration.xml
new file mode 100644 (file)
index 0000000..e56f225
--- /dev/null
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <!-- Flag to configure OAuth availability in the app.
+        3 valid values now: on, off, optional  
+     -->
+    <string name="oauth2_mode">off</string>
+    
+    <!-- constants that must be respected by the authorization server; if changed, the app must be rebuild -->
+    <string name="oauth2_redirect_scheme">owncloud</string>
+    <string name="oauth2_redirect_uri">owncloud://callback</string>
+    
+    <!-- values that should be provided by ownCloud server -->
+    <string name="oauth2_url_endpoint_auth">http://owncloud.tuxed.net/oauth/php-oauth/authorize.php</string>
+    <string name="oauth2_url_endpoint_access">http://owncloud.tuxed.net/oauth/php-oauth/token.php</string>
+    <string name="oauth2_scope">owncloud</string>
+    <string name="oauth2_grant_type">authorization_code</string>       <!-- the only one supported right now -->
+    <string name="oauth2_response_type">code</string>                          <!-- depends on oauth2_grant_type -->
+    
+    <!-- values that should be agreed between app and authorization server, but can be loaded without rebuilding the app -->
+    <string name="oauth2_client_id">com.owncloud.android</string>      <!-- preferable that client decides this -->
+    <string name="oauth2_client_secret"></string>                                      <!-- preferable that client decides this -->
+    
+</resources>
index 1c2ad7d..7520dc6 100644 (file)
     <string name="sync_string_contacts">Contacts</string>
     <string name="sync_fail_ticker">Synchronization failed</string>
     <string name="sync_fail_content">Synchronization of %1$s could not be completed</string>
-    <string name="sync_conflicts_in_favourites_ticker">Conflicts found</string>
-    <string name="sync_conflicts_in_favourites_content">%1$d kept-in-sync files could not be sync\'ed</string>
+    <string name="sync_fail_content_unauthorized">Invalid credentials for %1$s</string>
+       <string name="sync_conflicts_in_favourites_ticker">Conflicts found</string>
+       <string name="sync_conflicts_in_favourites_content">%1$d kept-in-sync files could not be sync\'ed</string>
     <string name="sync_fail_in_favourites_ticker">Kept-in-sync files failed</string>
     <string name="sync_fail_in_favourites_content">Contents of %1$d files could not be sync\'ed (%2$d conflicts)</string>
     <string name="sync_foreign_files_forgotten_ticker">Some local files were forgotten</string>
     <string name="auth_wrong_connection_title">Couldn\'t establish connection</string>
     <string name="auth_secure_connection">Secure connection established</string>
     <string name="auth_login_details">Login details</string>
-    <string name="auth_unauthorized">Invalid login / password</string>
+    <string name="auth_unauthorized">Invalid credentials</string>
+       <string name="auth_oauth_error">Unsuccessful authorization</string>
+       <string name="auth_oauth_error_access_denied">Access denied by authorization server</string>
     <string name="auth_not_found">Wrong path given</string>
     <string name="auth_internal">Internal server error, code %1$d</string>
+    <string name="auth_wtf_reenter_URL">Unexpected state; please, enter the server URL again</string>
+    <string name="auth_expired_oauth_token_toast">Your authorization expired.\nPlease, authorize again</string>
+    <string name="auth_expired_basic_auth_toast">Your saved credentials are invalid.\nPlease, enter the current credentials</string>
+    
     <string name="crashlog_message">Application terminated unexpectedly. Would you like to submit a crash report?</string>
     <string name="crashlog_send_report">Send report</string>
     <string name="crashlog_dont_send_report">Don\'t send report</string>
     <string name="wait_a_moment">Wait a moment</string>
     <string name="filedisplay_unexpected_bad_get_content">"Unexpected problem ; please select the file from a different app"</string>
     <string name="filedisplay_no_file_selected">No file was selected</string>
+    
+    <string name="oauth_host_url">oAuth2 URL</string> 
+    <string name="oauth_check_onoff">Login with oAuth2.</string> 
+    <string name="oauth_login_connection">Connecting to oAuth2 server…</string>    
+    <string name="oauth_code_validation_message">Please, open a web browser and go to:\n%1$s.\nValidate this code there:\n%2$s</string>
+    <string name="oauth_connection_url_unavailable">Connection to this URL not available.</string> 
+        
     <string name="ssl_validator_title">Warning</string>
     <string name="ssl_validator_header">The identity of the site could not be verified</string>
     <string name="ssl_validator_reason_cert_not_trusted">- The server certificate is not trusted</string>
index a02128f..161f5d3 100644 (file)
                <item name="android:singleLine">true</item>
                    
     </style>
+       
+       <style name="OAuthDialog" parent="@android:style/Theme.Dialog">
+               <item name="android:windowNoTitle">false</item> 
+       </style>    
                
        <color name="setup_text_hint">#777777</color>
        <color name="setup_text_typed">#000000</color>
index f064ce2..a1d39ae 100644 (file)
@@ -18,7 +18,7 @@
 \r
 package com.owncloud.android;\r
 \r
-import com.owncloud.android.authenticator.AccountAuthenticator;\r
+import com.owncloud.android.authentication.AccountAuthenticator;\r
 import com.owncloud.android.utils.OwnCloudVersion;\r
 \r
 import android.accounts.Account;\r
@@ -31,6 +31,7 @@ public class AccountUtils {
     public static final String WEBDAV_PATH_1_2 = "/webdav/owncloud.php";\r
     public static final String WEBDAV_PATH_2_0 = "/files/webdav.php";\r
     public static final String WEBDAV_PATH_4_0 = "/remote.php/webdav";\r
+    private static final String ODAV_PATH = "/remote.php/odav";\r
     public static final String CARDDAV_PATH_2_0 = "/apps/contacts/carddav.php";\r
     public static final String CARDDAV_PATH_4_0 = "/remote/carddav.php";\r
     public static final String STATUS_PATH = "/status.php";\r
@@ -112,8 +113,11 @@ public class AccountUtils {
      * @param version version of owncloud\r
      * @return webdav path for given OC version, null if OC version unknown\r
      */\r
-    public static String getWebdavPath(OwnCloudVersion version) {\r
+    public static String getWebdavPath(OwnCloudVersion version, boolean supportsOAuth) {\r
         if (version != null) {\r
+            if (supportsOAuth) {\r
+                return ODAV_PATH;\r
+            }\r
             if (version.compareTo(OwnCloudVersion.owncloud_v4) >= 0)\r
                 return WEBDAV_PATH_4_0;\r
             if (version.compareTo(OwnCloudVersion.owncloud_v3) >= 0\r
@@ -136,8 +140,9 @@ public class AccountUtils {
             AccountManager ama = AccountManager.get(context);\r
             String baseurl = ama.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL);\r
             String strver  = ama.getUserData(account, AccountAuthenticator.KEY_OC_VERSION);\r
+            boolean supportsOAuth = (ama.getUserData(account, AccountAuthenticator.KEY_SUPPORTS_OAUTH2) != null);\r
             OwnCloudVersion ver = new OwnCloudVersion(strver);\r
-            String webdavpath = getWebdavPath(ver);\r
+            String webdavpath = getWebdavPath(ver, supportsOAuth);\r
 \r
             if (webdavpath == null) return null;\r
             return baseurl + webdavpath;\r
index 70d5328..d2939c8 100644 (file)
@@ -24,8 +24,6 @@ import java.util.HashMap;
 import java.util.HashSet;\r
 import java.util.Set;\r
 \r
-import android.util.Log;\r
-\r
 /**\r
  * A helper class for some string operations.\r
  * \r
index 7c402c9..2ee5b4b 100644 (file)
@@ -15,6 +15,7 @@
  *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  *
  */
+
 package com.owncloud.android;
 
 import java.io.File;
@@ -25,12 +26,11 @@ import java.util.List;
 import java.util.Stack;
 import java.util.Vector;
 
-import com.owncloud.android.authenticator.AccountAuthenticator;
+import com.owncloud.android.authentication.AccountAuthenticator;
 import com.owncloud.android.datamodel.DataStorageManager;
 import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.files.services.FileUploader;
-import com.owncloud.android.network.OwnCloudClientUtils;
 
 import android.accounts.Account;
 import android.accounts.AccountManager;
@@ -49,7 +49,6 @@ import android.net.Uri;
 import android.os.Bundle;
 import android.os.Parcelable;
 import android.provider.MediaStore.Images.Media;
-import android.util.Log;
 import android.view.View;
 import android.view.Window;
 import android.widget.AdapterView;
@@ -60,7 +59,6 @@ import android.widget.SimpleAdapter;
 import android.widget.Toast;
 
 import com.owncloud.android.R;
-import eu.alefzero.webdav.WebdavClient;
 
 /**
  * This can be used to upload things to an ownCloud instance.
@@ -140,8 +138,8 @@ public class Uploader extends ListActivity implements OnItemClickListener, andro
                         // 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 });
+                        Intent intent = new Intent(android.provider.Settings.ACTION_ADD_ACCOUNT);
+                        intent.putExtra("authorities", new String[] { AccountAuthenticator.AUTHORITY });
                         startActivityForResult(intent, REQUEST_CODE_SETUP_ACCOUNT);
                     } else {
                         // since in API7 there is no direct call for
@@ -357,12 +355,13 @@ public class Uploader extends ListActivity implements OnItemClickListener, andro
 
     public void uploadFiles() {
         try {
+            /* TODO - mCreateDir can never be true at this moment; we will replace wdc.createDirectory by CreateFolderOperation when that is fixed 
             WebdavClient wdc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getApplicationContext());
-
             // create last directory in path if necessary
             if (mCreateDir) {
                 wdc.createDirectory(mUploadPath);
             }
+            */
 
             String[] local = new String[mStreamsToUpload.size()], remote = new String[mStreamsToUpload.size()];
 
diff --git a/src/com/owncloud/android/authentication/AccountAuthenticator.java b/src/com/owncloud/android/authentication/AccountAuthenticator.java
new file mode 100644 (file)
index 0000000..aa12993
--- /dev/null
@@ -0,0 +1,315 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2012  Bartek Przybylski
+ *   Copyright (C) 2012-2013 ownCloud Inc.
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License version 2,
+ *   as published by the Free Software Foundation.
+ *
+ *   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 com.owncloud.android.authentication;
+
+import android.accounts.*;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import com.owncloud.android.Log_OC;
+
+/**
+ *  Authenticator for ownCloud accounts.
+ * 
+ *  Controller class accessed from the system AccountManager, providing integration of ownCloud accounts with the Android system.
+ * 
+ *  TODO - better separation in operations for OAuth-capable and regular ownCloud accounts.
+ *  TODO - review completeness 
+ * 
+ * @author David A. Velasco
+ */
+public class AccountAuthenticator extends AbstractAccountAuthenticator {
+    
+    /**
+     * Is used by android system to assign accounts to authenticators. Should be
+     * used by application and all extensions.
+     */
+    public static final String ACCOUNT_TYPE = "owncloud";
+    public static final String AUTHORITY = "org.owncloud";
+    public static final String AUTH_TOKEN_TYPE = "org.owncloud";
+    public static final String AUTH_TOKEN_TYPE_PASSWORD = "owncloud.password";
+    public static final String AUTH_TOKEN_TYPE_ACCESS_TOKEN = "owncloud.oauth2.access_token";
+    public static final String AUTH_TOKEN_TYPE_REFRESH_TOKEN = "owncloud.oauth2.refresh_token";
+
+    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";
+    
+    /**
+     * Value under this key should handle path to webdav php script. Will be
+     * removed and usage should be replaced by combining
+     * {@link com.owncloud.android.authentication.AuthenticatorActivity.KEY_OC_BASE_URL} and
+     * {@link com.owncloud.android.utils.OwnCloudVersion}
+     * 
+     * @deprecated
+     */
+    public static final String KEY_OC_URL = "oc_url";
+    /**
+     * Version should be 3 numbers separated by dot so it can be parsed by
+     * {@link com.owncloud.android.utils.OwnCloudVersion}
+     */
+    public static final String KEY_OC_VERSION = "oc_version";
+    /**
+     * Base url should point to owncloud installation without trailing / ie:
+     * http://server/path or https://owncloud.server
+     */
+    public static final String KEY_OC_BASE_URL = "oc_base_url";
+    /**
+     * Flag signaling if the ownCloud server can be accessed with OAuth2 access tokens.
+     */
+    public static final String KEY_SUPPORTS_OAUTH2 = "oc_supports_oauth2";
+    
+    private static final String TAG = AccountAuthenticator.class.getSimpleName();
+    
+    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_OC.i(TAG, "Adding account with type " + accountType
+                + " and auth token " + authTokenType);
+        try {
+            validateAccountType(accountType);
+        } catch (AuthenticatorException e) {
+            Log_OC.e(TAG, "Failed to validate account type " + accountType + ": "
+                    + e.getMessage());
+            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);
+        intent.putExtra(AuthenticatorActivity.EXTRA_ACTION, AuthenticatorActivity.ACTION_CREATE);
+
+        setIntentFlags(intent);
+        
+        final Bundle bundle = new Bundle();
+        bundle.putParcelable(AccountManager.KEY_INTENT, intent);
+        return bundle;
+    }
+
+    /**\r
+     * {@inheritDoc}\r
+     */\r
+    @Override\r
+    public Bundle confirmCredentials(AccountAuthenticatorResponse response,\r
+            Account account, Bundle options) throws NetworkErrorException {\r
+        try {\r
+            validateAccountType(account.type);\r
+        } catch (AuthenticatorException e) {\r
+            Log_OC.e(TAG, "Failed to validate account type " + account.type + ": "\r
+                    + e.getMessage());\r
+            e.printStackTrace();\r
+            return e.getFailureBundle();\r
+        }\r
+        Intent intent = new Intent(mContext, AuthenticatorActivity.class);\r
+        intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE,\r
+                response);\r
+        intent.putExtra(KEY_ACCOUNT, account);\r
+        intent.putExtra(KEY_LOGIN_OPTIONS, options);\r
+\r
+        setIntentFlags(intent);\r
+\r
+        Bundle resultBundle = new Bundle();\r
+        resultBundle.putParcelable(AccountManager.KEY_INTENT, intent);\r
+        return resultBundle;\r
+    }\r
+\r
+    @Override\r
+    public Bundle editProperties(AccountAuthenticatorResponse response,\r
+            String accountType) {\r
+        return null;\r
+    }\r
+\r
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Bundle getAuthToken(AccountAuthenticatorResponse response,
+            Account account, String authTokenType, Bundle options)
+            throws NetworkErrorException {
+        /// validate parameters
+        try {
+            validateAccountType(account.type);
+            validateAuthTokenType(authTokenType);
+        } catch (AuthenticatorException e) {
+            Log_OC.e(TAG, "Failed to validate account type " + account.type + ": "
+                    + e.getMessage());
+            e.printStackTrace();
+            return e.getFailureBundle();
+        }
+        
+        /// check if required token is stored
+        final AccountManager am = AccountManager.get(mContext);
+        String accessToken;
+        if (authTokenType.equals(AUTH_TOKEN_TYPE_PASSWORD)) {
+            accessToken = am.getPassword(account);
+        } else {
+            accessToken = am.peekAuthToken(account, authTokenType);
+        }
+        if (accessToken != 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, accessToken);
+            return result;
+        }
+        
+        /// if not stored, return Intent to access the AuthenticatorActivity and UPDATE the token for the account
+        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.EXTRA_ACCOUNT, account);
+        intent.putExtra(AuthenticatorActivity.EXTRA_ACTION, AuthenticatorActivity.ACTION_UPDATE_TOKEN);
+        
+
+        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, true);
+        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_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)\r
+            throws UnsupportedAuthTokenTypeException {\r
+        if (!authTokenType.equals(AUTH_TOKEN_TYPE) &&\r
+            !authTokenType.equals(AUTH_TOKEN_TYPE_PASSWORD) &&\r
+            !authTokenType.equals(AUTH_TOKEN_TYPE_ACCESS_TOKEN) &&\r
+            !authTokenType.equals(AUTH_TOKEN_TYPE_REFRESH_TOKEN) ) {\r
+            throw new UnsupportedAuthTokenTypeException();\r
+        }\r
+    }\r
+\r
+    public static class AuthenticatorException extends Exception {\r
+        private static final long serialVersionUID = 1L;\r
+        private Bundle mFailureBundle;\r
+\r
+        public AuthenticatorException(int code, String errorMsg) {\r
+            mFailureBundle = new Bundle();\r
+            mFailureBundle.putInt(AccountManager.KEY_ERROR_CODE, code);\r
+            mFailureBundle\r
+                    .putString(AccountManager.KEY_ERROR_MESSAGE, errorMsg);\r
+        }\r
+\r
+        public Bundle getFailureBundle() {\r
+            return mFailureBundle;\r
+        }\r
+    }\r
+\r
+    public static class UnsupportedAccountTypeException extends\r
+            AuthenticatorException {\r
+        private static final long serialVersionUID = 1L;\r
+\r
+        public UnsupportedAccountTypeException() {\r
+            super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION,\r
+                    "Unsupported account type");\r
+        }\r
+    }\r
+\r
+    public static class UnsupportedAuthTokenTypeException extends\r
+            AuthenticatorException {\r
+        private static final long serialVersionUID = 1L;\r
+\r
+        public UnsupportedAuthTokenTypeException() {\r
+            super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION,\r
+                    "Unsupported auth token type");\r
+        }\r
+    }\r
+\r
+    public static class UnsupportedFeaturesException extends\r
+            AuthenticatorException {\r
+        public static final long serialVersionUID = 1L;\r
+\r
+        public UnsupportedFeaturesException() {\r
+            super(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION,\r
+                    "Unsupported features");\r
+        }\r
+    }\r
+\r
+    public static class AccessDeniedException extends AuthenticatorException {\r
+        public AccessDeniedException(int code, String errorMsg) {\r
+            super(AccountManager.ERROR_CODE_INVALID_RESPONSE, "Access Denied");\r
+        }\r
+\r
+        private static final long serialVersionUID = 1L;\r
+\r
+    }\r
+}\r
diff --git a/src/com/owncloud/android/authentication/AccountAuthenticatorService.java b/src/com/owncloud/android/authentication/AccountAuthenticatorService.java
new file mode 100644 (file)
index 0000000..c6a77d5
--- /dev/null
@@ -0,0 +1,41 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2011  Bartek Przybylski
+ *   Copyright (C) 2012-2013 ownCloud Inc.
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License version 2,
+ *   as published by the Free Software Foundation.
+ *
+ *   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 com.owncloud.android.authentication;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+public class AccountAuthenticatorService extends Service {
+
+    private AccountAuthenticator mAuthenticator;
+    static final public String ACCOUNT_TYPE = "owncloud";
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        mAuthenticator = new AccountAuthenticator(this);
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return mAuthenticator.getIBinder();
+    }
+
+}
diff --git a/src/com/owncloud/android/authentication/AuthenticatorActivity.java b/src/com/owncloud/android/authentication/AuthenticatorActivity.java
new file mode 100644 (file)
index 0000000..ef5c21b
--- /dev/null
@@ -0,0 +1,1085 @@
+/* ownCloud Android client application\r
+ *   Copyright (C) 2012  Bartek Przybylski\r
+ *   Copyright (C) 2012-2013 ownCloud Inc.\r
+ *\r
+ *   This program is free software: you can redistribute it and/or modify\r
+ *   it under the terms of the GNU General Public License version 2,\r
+ *   as published by the Free Software Foundation.\r
+ *\r
+ *   This program is distributed in the hope that it will be useful,\r
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ *   GNU General Public License for more details.\r
+ *\r
+ *   You should have received a copy of the GNU General Public License\r
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.\r
+ *\r
+ */\r
+\r
+package com.owncloud.android.authentication;\r
+\r
+import com.owncloud.android.AccountUtils;\r
+import com.owncloud.android.Log_OC;\r
+import com.owncloud.android.ui.dialog.SslValidatorDialog;\r
+import com.owncloud.android.ui.dialog.SslValidatorDialog.OnSslValidatorListener;\r
+import com.owncloud.android.utils.OwnCloudVersion;\r
+import com.owncloud.android.network.OwnCloudClientUtils;\r
+import com.owncloud.android.operations.OwnCloudServerCheckOperation;\r
+import com.owncloud.android.operations.ExistenceCheckOperation;\r
+import com.owncloud.android.operations.OAuth2GetAccessToken;\r
+import com.owncloud.android.operations.OnRemoteOperationListener;\r
+import com.owncloud.android.operations.RemoteOperation;\r
+import com.owncloud.android.operations.RemoteOperationResult;\r
+import com.owncloud.android.operations.RemoteOperationResult.ResultCode;\r
+\r
+import android.accounts.Account;\r
+import android.accounts.AccountAuthenticatorActivity;\r
+import android.accounts.AccountManager;\r
+import android.app.AlertDialog;\r
+import android.app.Dialog;\r
+import android.app.ProgressDialog;\r
+import android.content.ContentResolver;\r
+import android.content.DialogInterface;\r
+import android.content.Intent;\r
+import android.content.SharedPreferences;\r
+import android.net.Uri;\r
+import android.os.Bundle;\r
+import android.os.Handler;\r
+import android.preference.PreferenceManager;\r
+import android.text.InputType;\r
+import android.view.View;\r
+import android.view.View.OnFocusChangeListener;\r
+import android.view.Window;\r
+import android.widget.CheckBox;\r
+import android.widget.EditText;\r
+import android.widget.Button;\r
+import android.widget.ImageView;\r
+import android.widget.TextView;\r
+import android.widget.Toast;\r
+\r
+import com.owncloud.android.R;\r
+\r
+import eu.alefzero.webdav.WebdavClient;\r
+\r
+/**\r
+ * This Activity is used to add an ownCloud account to the App\r
+ * \r
+ * @author Bartek Przybylski\r
+ * @author David A. Velasco\r
+ */\r
+public class AuthenticatorActivity extends AccountAuthenticatorActivity\r
+        implements  OnRemoteOperationListener, OnSslValidatorListener, OnFocusChangeListener {\r
+\r
+    private static final String TAG = AuthenticatorActivity.class.getSimpleName();\r
+\r
+    public static final String EXTRA_ACCOUNT = "ACCOUNT";\r
+    public static final String EXTRA_USER_NAME = "USER_NAME";\r
+    public static final String EXTRA_HOST_NAME = "HOST_NAME";\r
+    public static final String EXTRA_ACTION = "ACTION";\r
+    \r
+    private static final String KEY_HOST_URL_TEXT = "HOST_URL_TEXT";\r
+    private static final String KEY_OC_VERSION = "OC_VERSION";\r
+    private static final String KEY_ACCOUNT = "ACCOUNT";\r
+    private static final String KEY_STATUS_TEXT = "STATUS_TEXT";\r
+    private static final String KEY_STATUS_ICON = "STATUS_ICON";\r
+    private static final String KEY_STATUS_CORRECT = "STATUS_CORRECT";\r
+    private static final String KEY_IS_SSL_CONN = "IS_SSL_CONN";\r
+    private static final String KEY_OAUTH2_STATUS_TEXT = "OAUTH2_STATUS_TEXT";\r
+    private static final String KEY_OAUTH2_STATUS_ICON = "OAUTH2_STATUS_ICON";\r
+    \r
+    private static final String OAUTH_MODE_ON = "on";\r
+    private static final String OAUTH_MODE_OFF = "off";\r
+    private static final String OAUTH_MODE_OPTIONAL = "optional";\r
+\r
+    private static final int DIALOG_LOGIN_PROGRESS = 0;\r
+    private static final int DIALOG_SSL_VALIDATOR = 1;\r
+    private static final int DIALOG_CERT_NOT_SAVED = 2;\r
+    private static final int DIALOG_OAUTH2_LOGIN_PROGRESS = 3;\r
+\r
+    public static final byte ACTION_CREATE = 0;\r
+    public static final byte ACTION_UPDATE_TOKEN = 1;\r
+\r
+    \r
+    private String mHostBaseUrl;\r
+    private OwnCloudVersion mDiscoveredVersion;\r
+    \r
+    private int mStatusText, mStatusIcon;\r
+    private boolean mStatusCorrect, mIsSslConn;\r
+    private int mOAuth2StatusText, mOAuth2StatusIcon;    \r
+    \r
+    private final Handler mHandler = new Handler();\r
+    private Thread mOperationThread;\r
+    private OwnCloudServerCheckOperation mOcServerChkOperation;\r
+    private ExistenceCheckOperation mAuthCheckOperation;\r
+    private RemoteOperationResult mLastSslUntrustedServerResult;\r
+\r
+    private Uri mNewCapturedUriFromOAuth2Redirection;\r
+    \r
+    private AccountManager mAccountMgr;\r
+    private boolean mJustCreated;\r
+    private byte mAction;\r
+    private Account mAccount;\r
+    \r
+    private ImageView mRefreshButton;\r
+    private ImageView mViewPasswordButton;\r
+    private EditText mHostUrlInput;\r
+    private EditText mUsernameInput;\r
+    private EditText mPasswordInput;\r
+    private CheckBox mOAuth2Check;\r
+    private String mOAuthAccessToken;\r
+    private View mOkButton;\r
+    private TextView mAuthStatusLayout;\r
+    \r
+    private TextView mOAuthAuthEndpointText;\r
+    private TextView mOAuthTokenEndpointText;\r
+    \r
+    \r
+    /**\r
+     * {@inheritDoc}\r
+     * \r
+     * IMPORTANT ENTRY POINT 1: activity is shown to the user\r
+     */\r
+    @Override\r
+    protected void onCreate(Bundle savedInstanceState) {\r
+        super.onCreate(savedInstanceState);\r
+        getWindow().requestFeature(Window.FEATURE_NO_TITLE);\r
+        \r
+        /// set view and get references to view elements\r
+        setContentView(R.layout.account_setup);\r
+        mRefreshButton = (ImageView) findViewById(R.id.refreshButton);\r
+        mViewPasswordButton = (ImageView) findViewById(R.id.viewPasswordButton);\r
+        mHostUrlInput = (EditText) findViewById(R.id.hostUrlInput);\r
+        mUsernameInput = (EditText) findViewById(R.id.account_username);\r
+        mPasswordInput = (EditText) findViewById(R.id.account_password);\r
+        mOAuthAuthEndpointText = (TextView)findViewById(R.id.oAuthEntryPoint_1);\r
+        mOAuthTokenEndpointText = (TextView)findViewById(R.id.oAuthEntryPoint_2);\r
+        mOAuth2Check = (CheckBox) findViewById(R.id.oauth_onOff_check);\r
+        mOkButton = findViewById(R.id.buttonOK);\r
+        mAuthStatusLayout = (TextView) findViewById(R.id.auth_status_text); \r
+        \r
+        /// complete label for 'register account' button\r
+        Button b = (Button) findViewById(R.id.account_register);\r
+        if (b != null) {\r
+            b.setText(String.format(getString(R.string.auth_register), getString(R.string.app_name)));\r
+        }\r
+\r
+        /// bind view elements to listeners\r
+        mHostUrlInput.setOnFocusChangeListener(this);\r
+        mPasswordInput.setOnFocusChangeListener(this);\r
+        \r
+        /// initialization\r
+        mAccountMgr = AccountManager.get(this);\r
+        mNewCapturedUriFromOAuth2Redirection = null;\r
+        mAction = getIntent().getByteExtra(EXTRA_ACTION, ACTION_CREATE); \r
+        mAccount = null;\r
+\r
+        if (savedInstanceState == null) {\r
+            /// connection state and info\r
+            mStatusText = mStatusIcon = 0;\r
+            mStatusCorrect = false;\r
+            mIsSslConn = false;\r
+            \r
+            /// retrieve extras from intent\r
+            String tokenType = getIntent().getExtras().getString(AccountAuthenticator.KEY_AUTH_TOKEN_TYPE);\r
+            boolean oAuthRequired = AccountAuthenticator.AUTH_TOKEN_TYPE_ACCESS_TOKEN.equals(tokenType) || OAUTH_MODE_ON.equals(getString(R.string.oauth2_mode));\r
+            \r
+            mAccount = getIntent().getExtras().getParcelable(EXTRA_ACCOUNT);\r
+            if (mAccount != null) {\r
+                String ocVersion = mAccountMgr.getUserData(mAccount, AccountAuthenticator.KEY_OC_VERSION);\r
+                if (ocVersion != null) {\r
+                    mDiscoveredVersion = new OwnCloudVersion(ocVersion);\r
+                }\r
+                mHostBaseUrl = mAccountMgr.getUserData(mAccount, AccountAuthenticator.KEY_OC_BASE_URL);\r
+                mHostUrlInput.setText(mHostBaseUrl);\r
+                String userName = mAccount.name.substring(0, mAccount.name.lastIndexOf('@'));\r
+                mUsernameInput.setText(userName);\r
+                oAuthRequired = (mAccountMgr.getUserData(mAccount, AccountAuthenticator.KEY_SUPPORTS_OAUTH2) != null);\r
+            }\r
+            mOAuth2Check.setChecked(oAuthRequired);\r
+            changeViewByOAuth2Check(oAuthRequired);\r
+            \r
+\r
+        } else {\r
+            loadSavedInstanceState(savedInstanceState);\r
+        }\r
+        \r
+        if (!OAUTH_MODE_OPTIONAL.equals(getString(R.string.oauth2_mode))) {\r
+            mOAuth2Check.setVisibility(View.GONE);\r
+        }\r
+        \r
+        if (mAction == ACTION_UPDATE_TOKEN) {\r
+            /// lock things that should not change\r
+            mHostUrlInput.setEnabled(false);\r
+            mUsernameInput.setEnabled(false);\r
+            mOAuth2Check.setVisibility(View.GONE);\r
+            checkOcServer(); \r
+        }\r
+        \r
+        mPasswordInput.setText("");     // clean password to avoid social hacking (disadvantage: password in removed if the device is turned aside)\r
+        mJustCreated = true;\r
+    }\r
+\r
+\r
+    /**\r
+     * Saves relevant state before {@link #onPause()}\r
+     * \r
+     * Do NOT save {@link #mNewCapturedUriFromOAuth2Redirection}; it keeps a temporal flag, intended to defer the \r
+     * processing of the redirection caught in {@link #onNewIntent(Intent)} until {@link #onResume()} \r
+     * \r
+     * See {@link #loadSavedInstanceState(Bundle)}\r
+     */\r
+    @Override\r
+    protected void onSaveInstanceState(Bundle outState) {\r
+        super.onSaveInstanceState(outState);\r
+        \r
+        /// connection state and info\r
+        outState.putInt(KEY_STATUS_TEXT, mStatusText);\r
+        outState.putInt(KEY_STATUS_ICON, mStatusIcon);\r
+        outState.putBoolean(KEY_STATUS_CORRECT, mStatusCorrect);\r
+        outState.putBoolean(KEY_IS_SSL_CONN, mIsSslConn);\r
+\r
+        /// server data\r
+        if (mDiscoveredVersion != null) \r
+            outState.putString(KEY_OC_VERSION, mDiscoveredVersion.toString());\r
+        outState.putString(KEY_HOST_URL_TEXT, mHostBaseUrl);\r
+        \r
+        /// account data, if updating\r
+        if (mAccount != null)\r
+            outState.putParcelable(KEY_ACCOUNT, mAccount);\r
+        \r
+        // Saving the state of oAuth2 components.\r
+        outState.putInt(KEY_OAUTH2_STATUS_ICON, mOAuth2StatusIcon);\r
+        outState.putInt(KEY_OAUTH2_STATUS_TEXT, mOAuth2StatusText);\r
+        \r
+    }\r
+\r
+\r
+    /**\r
+     * Loads saved state\r
+     * \r
+     * See {@link #onSaveInstanceState(Bundle)}.\r
+     * \r
+     * @param savedInstanceState    Saved state, as received in {@link #onCreate(Bundle)}.\r
+     */\r
+    private void loadSavedInstanceState(Bundle savedInstanceState) {\r
+        /// connection state and info\r
+        mStatusCorrect = savedInstanceState.getBoolean(KEY_STATUS_CORRECT);\r
+        mIsSslConn = savedInstanceState.getBoolean(KEY_IS_SSL_CONN);\r
+        mStatusText = savedInstanceState.getInt(KEY_STATUS_TEXT);\r
+        mStatusIcon = savedInstanceState.getInt(KEY_STATUS_ICON);\r
+        updateConnStatus();\r
+        \r
+        /// UI settings depending upon connection\r
+        mOkButton.setEnabled(mStatusCorrect);   // TODO really necessary?\r
+        if (!mStatusCorrect)\r
+            mRefreshButton.setVisibility(View.VISIBLE); // seems that setting visibility is necessary\r
+        else\r
+            mRefreshButton.setVisibility(View.INVISIBLE);\r
+        \r
+        /// server data\r
+        String ocVersion = savedInstanceState.getString(KEY_OC_VERSION);\r
+        if (ocVersion != null)\r
+            mDiscoveredVersion = new OwnCloudVersion(ocVersion);\r
+        mHostBaseUrl = savedInstanceState.getString(KEY_HOST_URL_TEXT);\r
+        \r
+        // account data, if updating\r
+        mAccount = savedInstanceState.getParcelable(KEY_ACCOUNT);\r
+        \r
+        // state of oAuth2 components\r
+        mOAuth2StatusIcon = savedInstanceState.getInt(KEY_OAUTH2_STATUS_ICON);\r
+        mOAuth2StatusText = savedInstanceState.getInt(KEY_OAUTH2_STATUS_TEXT);\r
+        // END of getting the state of oAuth2 components.\r
+    }\r
+\r
+    \r
+    /**\r
+     * The redirection triggered by the OAuth authentication server as response to the GET AUTHORIZATION request\r
+     * is caught here.\r
+     * \r
+     * To make this possible, this activity needs to be qualified with android:launchMode = "singleTask" in the\r
+     * AndroidManifest.xml file.\r
+     */\r
+    @Override\r
+    protected void onNewIntent (Intent intent) {\r
+        Log_OC.d(TAG, "onNewIntent()");\r
+        Uri data = intent.getData();\r
+        if (data != null && data.toString().startsWith(getString(R.string.oauth2_redirect_uri))) {\r
+            mNewCapturedUriFromOAuth2Redirection = data;\r
+        }\r
+    }\r
+\r
+    \r
+    /**\r
+     * The redirection triggered by the OAuth authentication server as response to the GET AUTHORIZATION, and \r
+     * deferred in {@link #onNewIntent(Intent)}, is processed here.\r
+     */\r
+    @Override\r
+    protected void onResume() {\r
+        super.onResume();\r
+        // the state of mOAuth2Check is automatically recovered between configuration changes, but not before onCreate() finishes; so keep the next lines here\r
+        changeViewByOAuth2Check(mOAuth2Check.isChecked());  \r
+        if (mAction == ACTION_UPDATE_TOKEN && mJustCreated) {\r
+            if (mOAuth2Check.isChecked())\r
+                Toast.makeText(this, R.string.auth_expired_oauth_token_toast, Toast.LENGTH_LONG).show();\r
+            else\r
+                Toast.makeText(this, R.string.auth_expired_basic_auth_toast, Toast.LENGTH_LONG).show();\r
+        }\r
+        \r
+        if (mNewCapturedUriFromOAuth2Redirection != null) {\r
+            getOAuth2AccessTokenFromCapturedRedirection();            \r
+        }\r
+        \r
+        mJustCreated = false;\r
+    }\r
+    \r
+    \r
+    /**\r
+     * Parses the redirection with the response to the GET AUTHORIZATION request to the \r
+     * oAuth server and requests for the access token (GET ACCESS TOKEN)\r
+     */\r
+    private void getOAuth2AccessTokenFromCapturedRedirection() {\r
+        /// Parse data from OAuth redirection\r
+        String queryParameters = mNewCapturedUriFromOAuth2Redirection.getQuery();\r
+        mNewCapturedUriFromOAuth2Redirection = null;\r
+        \r
+        /// Showing the dialog with instructions for the user.\r
+        showDialog(DIALOG_OAUTH2_LOGIN_PROGRESS);\r
+\r
+        /// GET ACCESS TOKEN to the oAuth server \r
+        RemoteOperation operation = new OAuth2GetAccessToken(   getString(R.string.oauth2_client_id), \r
+                                                                getString(R.string.oauth2_redirect_uri), // TODO check - necessary here?      \r
+                                                                getString(R.string.oauth2_grant_type),\r
+                                                                queryParameters);\r
+        //WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(getString(R.string.oauth2_url_endpoint_access)), getApplicationContext());\r
+        WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(mOAuthTokenEndpointText.getText().toString().trim()), getApplicationContext());\r
+        operation.execute(client, this, mHandler);\r
+    }\r
+    \r
+\r
+    \r
+    /**\r
+     * Handles the change of focus on the text inputs for the server URL and the password\r
+     */\r
+    public void onFocusChange(View view, boolean hasFocus) {\r
+        if (view.getId() == R.id.hostUrlInput) {\r
+            onUrlInputFocusChanged((TextView) view, hasFocus);\r
+            \r
+        } else if (view.getId() == R.id.account_password) {\r
+            onPasswordFocusChanged((TextView) view, hasFocus);\r
+        }\r
+    }\r
+    \r
+\r
+    /**\r
+     * Handles changes in focus on the text input for the server URL.\r
+     * \r
+     * IMPORTANT ENTRY POINT 2: When (!hasFocus), user wrote the server URL and changed to \r
+     * other field. The operation to check the existence of the server in the entered URL is\r
+     * started. \r
+     * \r
+     * When hasFocus:    user 'comes back' to write again the server URL.\r
+     * \r
+     * @param hostInput     TextView with the URL input field receiving the change of focus.\r
+     * @param hasFocus      'True' if focus is received, 'false' if is lost\r
+     */\r
+    private void onUrlInputFocusChanged(TextView hostInput, boolean hasFocus) {\r
+        if (!hasFocus) {\r
+            checkOcServer();\r
+            \r
+        } else {\r
+            // avoids that the 'connect' button can be clicked if the test was previously passed\r
+            mOkButton.setEnabled(false); \r
+        }\r
+    }\r
+\r
+\r
+    private void checkOcServer() {\r
+        String uri = mHostUrlInput.getText().toString().trim();\r
+        if (uri.length() != 0) {\r
+            mStatusText = R.string.auth_testing_connection;\r
+            mStatusIcon = R.drawable.progress_small;\r
+            updateConnStatus();\r
+            /** TODO cancel previous connection check if the user tries to ammend a wrong URL  \r
+            if(mConnChkOperation != null) {\r
+                mConnChkOperation.cancel();\r
+            } */\r
+            mOcServerChkOperation = new  OwnCloudServerCheckOperation(uri, this);\r
+            WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(uri), this);\r
+            mHostBaseUrl = "";\r
+            mDiscoveredVersion = null;\r
+            mOperationThread = mOcServerChkOperation.execute(client, this, mHandler);\r
+        } else {\r
+            mRefreshButton.setVisibility(View.INVISIBLE);\r
+            mStatusText = 0;\r
+            mStatusIcon = 0;\r
+            updateConnStatus();\r
+        }\r
+    }\r
+\r
+\r
+    /**\r
+     * Handles changes in focus on the text input for the password (basic authorization).\r
+     * \r
+     * When (hasFocus), the button to toggle password visibility is shown.\r
+     * \r
+     * When (!hasFocus), the button is made invisible and the password is hidden.\r
+     * \r
+     * @param passwordInput    TextView with the password input field receiving the change of focus.\r
+     * @param hasFocus          'True' if focus is received, 'false' if is lost\r
+     */\r
+    private void onPasswordFocusChanged(TextView passwordInput, boolean hasFocus) {\r
+        if (hasFocus) {\r
+            mViewPasswordButton.setVisibility(View.VISIBLE);\r
+        } else {\r
+            int input_type = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD;\r
+            passwordInput.setInputType(input_type);\r
+            mViewPasswordButton.setVisibility(View.INVISIBLE);\r
+        }\r
+    }\r
+\r
+\r
+    \r
+    /**\r
+     * Cancels the authenticator activity\r
+     * \r
+     * IMPORTANT ENTRY POINT 3: Never underestimate the importance of cancellation\r
+     * \r
+     * This method is bound in the layout/acceoun_setup.xml resource file.\r
+     * \r
+     * @param view      Cancel button\r
+     */\r
+    public void onCancelClick(View view) {\r
+        setResult(RESULT_CANCELED);     // TODO review how is this related to AccountAuthenticator (debugging)\r
+        finish();\r
+    }\r
+    \r
+    \r
+    \r
+    /**\r
+     * Checks the credentials of the user in the root of the ownCloud server\r
+     * before creating a new local account.\r
+     * \r
+     * For basic authorization, a check of existence of the root folder is\r
+     * performed.\r
+     * \r
+     * For OAuth, starts the flow to get an access token; the credentials test \r
+     * is postponed until it is available.\r
+     * \r
+     * IMPORTANT ENTRY POINT 4\r
+     * \r
+     * @param view      OK button\r
+     */\r
+    public void onOkClick(View view) {\r
+        // this check should be unnecessary\r
+        if (mDiscoveredVersion == null || !mDiscoveredVersion.isVersionValid()  || mHostBaseUrl == null || mHostBaseUrl.length() == 0) {\r
+            mStatusIcon = R.drawable.common_error;\r
+            mStatusText = R.string.auth_wtf_reenter_URL;\r
+            updateConnStatus();\r
+            mOkButton.setEnabled(false);\r
+            Log_OC.wtf(TAG,  "The user was allowed to click 'connect' to an unchecked server!!");\r
+            return;\r
+        }\r
+        \r
+        if (mOAuth2Check.isChecked()) {\r
+            startOauthorization();\r
+            \r
+        } else {\r
+            checkBasicAuthorization();\r
+        }\r
+    }\r
+    \r
+    \r
+    /**\r
+     * Tests the credentials entered by the user performing a check of existence on \r
+     * the root folder of the ownCloud server.\r
+     */\r
+    private void checkBasicAuthorization() {\r
+        /// get the path to the root folder through WebDAV from the version server\r
+        String webdav_path = AccountUtils.getWebdavPath(mDiscoveredVersion, false);\r
+        \r
+        /// get basic credentials entered by user\r
+        String username = mUsernameInput.getText().toString();\r
+        String password = mPasswordInput.getText().toString();\r
+        \r
+        /// be gentle with the user\r
+        showDialog(DIALOG_LOGIN_PROGRESS);\r
+        \r
+        /// test credentials accessing the root folder\r
+        mAuthCheckOperation = new  ExistenceCheckOperation("", this, false);\r
+        WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(mHostBaseUrl + webdav_path), this);\r
+        client.setBasicCredentials(username, password);\r
+        mOperationThread = mAuthCheckOperation.execute(client, this, mHandler);\r
+    }\r
+\r
+\r
+    /**\r
+     * Starts the OAuth 'grant type' flow to get an access token, with \r
+     * a GET AUTHORIZATION request to the BUILT-IN authorization server. \r
+     */\r
+    private void startOauthorization() {\r
+        // be gentle with the user\r
+        mStatusIcon = R.drawable.progress_small;\r
+        mStatusText = R.string.oauth_login_connection;\r
+        updateAuthStatus();\r
+        \r
+        // GET AUTHORIZATION request\r
+        //Uri uri = Uri.parse(getString(R.string.oauth2_url_endpoint_auth));\r
+        Uri uri = Uri.parse(mOAuthAuthEndpointText.getText().toString().trim());\r
+        Uri.Builder uriBuilder = uri.buildUpon();\r
+        uriBuilder.appendQueryParameter(OAuth2Constants.KEY_RESPONSE_TYPE, getString(R.string.oauth2_response_type));\r
+        uriBuilder.appendQueryParameter(OAuth2Constants.KEY_REDIRECT_URI, getString(R.string.oauth2_redirect_uri));   \r
+        uriBuilder.appendQueryParameter(OAuth2Constants.KEY_CLIENT_ID, getString(R.string.oauth2_client_id));\r
+        uriBuilder.appendQueryParameter(OAuth2Constants.KEY_SCOPE, getString(R.string.oauth2_scope));\r
+        //uriBuilder.appendQueryParameter(OAuth2Constants.KEY_STATE, whateverwewant);\r
+        uri = uriBuilder.build();\r
+        Log_OC.d(TAG, "Starting browser to view " + uri.toString());\r
+        Intent i = new Intent(Intent.ACTION_VIEW, uri);\r
+        startActivity(i);\r
+    }\r
+\r
+    \r
+    /**\r
+     * Callback method invoked when a RemoteOperation executed by this Activity finishes.\r
+     * \r
+     * Dispatches the operation flow to the right method.\r
+     */\r
+    @Override\r
+    public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {\r
+\r
+        if (operation instanceof OwnCloudServerCheckOperation) {\r
+            onOcServerCheckFinish((OwnCloudServerCheckOperation) operation, result);\r
+            \r
+        } else if (operation instanceof OAuth2GetAccessToken) {\r
+            onGetOAuthAccessTokenFinish((OAuth2GetAccessToken)operation, result);\r
+                \r
+        } else if (operation instanceof ExistenceCheckOperation)  {\r
+            onAuthorizationCheckFinish((ExistenceCheckOperation)operation, result);\r
+                \r
+        }\r
+    }\r
+    \r
+\r
+    /**\r
+     * Processes the result of the server check performed when the user finishes the enter of the\r
+     * server URL.\r
+     * \r
+     * @param operation     Server check performed.\r
+     * @param result        Result of the check.\r
+     */\r
+    private void onOcServerCheckFinish(OwnCloudServerCheckOperation operation, RemoteOperationResult result) {\r
+        /// update status icon and text\r
+        updateStatusIconAndText(result);\r
+        updateConnStatus();\r
+\r
+        /// save result state\r
+        mStatusCorrect = result.isSuccess();\r
+        mIsSslConn = (result.getCode() == ResultCode.OK_SSL);\r
+        \r
+        /// very special case (TODO: move to a common place for all the remote operations)\r
+        if (result.getCode() == ResultCode.SSL_RECOVERABLE_PEER_UNVERIFIED) {\r
+            mLastSslUntrustedServerResult = result;\r
+            showDialog(DIALOG_SSL_VALIDATOR); \r
+        }\r
+        \r
+        /// update the visibility of the 'retry connection' button\r
+        if (!mStatusCorrect)\r
+            mRefreshButton.setVisibility(View.VISIBLE);\r
+        else\r
+            mRefreshButton.setVisibility(View.INVISIBLE);\r
+        \r
+        /// retrieve discovered version and normalize server URL\r
+        mDiscoveredVersion = operation.getDiscoveredVersion();\r
+        mHostBaseUrl = mHostUrlInput.getText().toString().trim();\r
+        if (!mHostBaseUrl.toLowerCase().startsWith("http://") &&\r
+            !mHostBaseUrl.toLowerCase().startsWith("https://")) {\r
+            \r
+            if (mIsSslConn) {\r
+                mHostBaseUrl = "https://" + mHostBaseUrl;\r
+            } else {\r
+                mHostBaseUrl = "http://" + mHostBaseUrl;\r
+            }\r
+            \r
+        }\r
+        if (mHostBaseUrl.endsWith("/"))\r
+            mHostBaseUrl = mHostBaseUrl.substring(0, mHostBaseUrl.length() - 1);\r
+        \r
+        /// allow or not the user try to access the server\r
+        mOkButton.setEnabled(mStatusCorrect);\r
+    }\r
+\r
+\r
+    /**\r
+     * Chooses the right icon and text to show to the user for the received operation result.\r
+     * \r
+     * @param result    Result of a remote operation performed in this activity\r
+     */\r
+    private void updateStatusIconAndText(RemoteOperationResult result) {\r
+        mStatusText = mStatusIcon = 0;\r
+\r
+        switch (result.getCode()) {\r
+        case OK_SSL:\r
+            mStatusIcon = android.R.drawable.ic_secure;\r
+            mStatusText = R.string.auth_secure_connection;\r
+            break;\r
+            \r
+        case OK_NO_SSL:\r
+        case OK:\r
+            if (mHostUrlInput.getText().toString().trim().toLowerCase().startsWith("http://") ) {\r
+                mStatusText = R.string.auth_connection_established;\r
+                mStatusIcon = R.drawable.ic_ok;\r
+            } else {\r
+                mStatusText = R.string.auth_nossl_plain_ok_title;\r
+                mStatusIcon = android.R.drawable.ic_partial_secure;\r
+            }\r
+            break;\r
+            \r
+        case SSL_RECOVERABLE_PEER_UNVERIFIED:\r
+            mStatusIcon = R.drawable.common_error;\r
+            mStatusText = R.string.auth_ssl_unverified_server_title;\r
+            break;\r
+                \r
+        case BAD_OC_VERSION:\r
+            mStatusIcon = R.drawable.common_error;\r
+            mStatusText = R.string.auth_bad_oc_version_title;\r
+            break;\r
+        case WRONG_CONNECTION:\r
+            mStatusIcon = R.drawable.common_error;\r
+            mStatusText = R.string.auth_wrong_connection_title;\r
+            break;\r
+        case TIMEOUT:\r
+            mStatusIcon = R.drawable.common_error;\r
+            mStatusText = R.string.auth_timeout_title;\r
+            break;\r
+        case INCORRECT_ADDRESS:\r
+            mStatusIcon = R.drawable.common_error;\r
+            mStatusText = R.string.auth_incorrect_address_title;\r
+            break;\r
+            \r
+        case SSL_ERROR:\r
+            mStatusIcon = R.drawable.common_error;\r
+            mStatusText = R.string.auth_ssl_general_error_title;\r
+            break;\r
+            \r
+        case UNAUTHORIZED:\r
+            mStatusIcon = R.drawable.common_error;\r
+            mStatusText = R.string.auth_unauthorized;\r
+            break;\r
+        case HOST_NOT_AVAILABLE:\r
+            mStatusIcon = R.drawable.common_error;\r
+            mStatusText = R.string.auth_unknown_host_title;\r
+            break;\r
+        case NO_NETWORK_CONNECTION:\r
+            mStatusIcon = R.drawable.no_network;\r
+            mStatusText = R.string.auth_no_net_conn_title;\r
+            break;\r
+        case INSTANCE_NOT_CONFIGURED:\r
+            mStatusIcon = R.drawable.common_error;\r
+            mStatusText = R.string.auth_not_configured_title;\r
+            break;\r
+        case FILE_NOT_FOUND:\r
+            mStatusIcon = R.drawable.common_error;\r
+            mStatusText = R.string.auth_incorrect_path_title;\r
+            break;\r
+        case OAUTH2_ERROR:\r
+            mStatusIcon = R.drawable.common_error;\r
+            mStatusText = R.string.auth_oauth_error;\r
+            break;\r
+        case OAUTH2_ERROR_ACCESS_DENIED:\r
+            mStatusIcon = R.drawable.common_error;\r
+            mStatusText = R.string.auth_oauth_error_access_denied;\r
+            break;\r
+        case UNHANDLED_HTTP_CODE:\r
+        case UNKNOWN_ERROR:\r
+            mStatusIcon = R.drawable.common_error;\r
+            mStatusText = R.string.auth_unknown_error_title;\r
+            break;\r
+            \r
+        default:\r
+            break;\r
+        }\r
+    }\r
+\r
+\r
+    /**\r
+     * Processes the result of the request for and access token send \r
+     * to an OAuth authorization server.\r
+     * \r
+     * @param operation     Operation performed requesting the access token.\r
+     * @param result        Result of the operation.\r
+     */\r
+    private void onGetOAuthAccessTokenFinish(OAuth2GetAccessToken operation, RemoteOperationResult result) {\r
+        try {\r
+            dismissDialog(DIALOG_OAUTH2_LOGIN_PROGRESS);\r
+        } catch (IllegalArgumentException e) {\r
+            // NOTHING TO DO ; can't find out what situation that leads to the exception in this code, but user logs signal that it happens\r
+        }\r
+\r
+        String webdav_path = AccountUtils.getWebdavPath(mDiscoveredVersion, true);\r
+        if (result.isSuccess() && webdav_path != null) {\r
+            /// be gentle with the user\r
+            showDialog(DIALOG_LOGIN_PROGRESS);\r
+            \r
+            /// time to test the retrieved access token on the ownCloud server\r
+            mOAuthAccessToken = ((OAuth2GetAccessToken)operation).getResultTokenMap().get(OAuth2Constants.KEY_ACCESS_TOKEN);\r
+            Log_OC.d(TAG, "Got ACCESS TOKEN: " + mOAuthAccessToken);\r
+            mAuthCheckOperation = new ExistenceCheckOperation("", this, false);\r
+            WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(mHostBaseUrl + webdav_path), this);\r
+            client.setBearerCredentials(mOAuthAccessToken);\r
+            mAuthCheckOperation.execute(client, this, mHandler);\r
+            \r
+        } else {\r
+            updateStatusIconAndText(result);\r
+            updateAuthStatus();\r
+            Log_OC.d(TAG, "Access failed: " + result.getLogMessage());\r
+        }\r
+    }\r
+\r
+    \r
+    /**\r
+     * Processes the result of the access check performed to try the user credentials.\r
+     * \r
+     * Creates a new account through the AccountManager.\r
+     * \r
+     * @param operation     Access check performed.\r
+     * @param result        Result of the operation.\r
+     */\r
+    private void onAuthorizationCheckFinish(ExistenceCheckOperation operation, RemoteOperationResult result) {\r
+        try {\r
+            dismissDialog(DIALOG_LOGIN_PROGRESS);\r
+        } catch (IllegalArgumentException e) {\r
+            // NOTHING TO DO ; can't find out what situation that leads to the exception in this code, but user logs signal that it happens\r
+        }\r
+        \r
+        if (result.isSuccess()) {\r
+            Log_OC.d(TAG, "Successful access - time to save the account");\r
+\r
+            if (mAction == ACTION_CREATE) {\r
+                createAccount();\r
+                \r
+            } else {\r
+                updateToken();\r
+            }\r
+            \r
+            finish();\r
+            \r
+        } else {\r
+            updateStatusIconAndText(result);\r
+            updateAuthStatus();\r
+            Log_OC.d(TAG, "Access failed: " + result.getLogMessage());\r
+        }\r
+    }\r
+\r
+    \r
+    /**\r
+     * Sets the proper response to get that the Account Authenticator that started this activity saves \r
+     * a new authorization token for mAccount.\r
+     */\r
+    private void updateToken() {\r
+        Bundle response = new Bundle();\r
+        response.putString(AccountManager.KEY_ACCOUNT_NAME, mAccount.name);\r
+        response.putString(AccountManager.KEY_ACCOUNT_TYPE, mAccount.type);\r
+        boolean isOAuth = mOAuth2Check.isChecked();\r
+        if (isOAuth) {\r
+            response.putString(AccountManager.KEY_AUTHTOKEN, mOAuthAccessToken);\r
+            // the next line is necessary; by now, notifications are calling directly to the AuthenticatorActivity to update, without AccountManager intervention\r
+            mAccountMgr.setAuthToken(mAccount, AccountAuthenticator.AUTH_TOKEN_TYPE_ACCESS_TOKEN, mOAuthAccessToken);\r
+        } else {\r
+            response.putString(AccountManager.KEY_AUTHTOKEN, mPasswordInput.getText().toString());\r
+            mAccountMgr.setPassword(mAccount, mPasswordInput.getText().toString());\r
+        }\r
+        setAccountAuthenticatorResult(response);\r
+    }\r
+\r
+\r
+    /**\r
+     * Creates a new account through the Account Authenticator that started this activity. \r
+     * \r
+     * This makes the account permanent.\r
+     * \r
+     * TODO Decide how to name the OAuth accounts\r
+     */\r
+    private void createAccount() {\r
+        /// create and save new ownCloud account\r
+        boolean isOAuth = mOAuth2Check.isChecked();\r
+        \r
+        Uri uri = Uri.parse(mHostBaseUrl);\r
+        String username = mUsernameInput.getText().toString().trim();\r
+        if (isOAuth) {\r
+            username = "OAuth_user" + (new java.util.Random(System.currentTimeMillis())).nextLong();\r
+        }            \r
+        String accountName = username + "@" + uri.getHost();\r
+        if (uri.getPort() >= 0) {\r
+            accountName += ":" + uri.getPort();\r
+        }\r
+        mAccount = new Account(accountName, AccountAuthenticator.ACCOUNT_TYPE);\r
+        if (isOAuth) {\r
+            mAccountMgr.addAccountExplicitly(mAccount, "", null);  // with our implementation, the password is never input in the app\r
+        } else {\r
+            mAccountMgr.addAccountExplicitly(mAccount, mPasswordInput.getText().toString(), null);\r
+        }\r
+\r
+        /// add the new account as default in preferences, if there is none already\r
+        Account defaultAccount = AccountUtils.getCurrentOwnCloudAccount(this);\r
+        if (defaultAccount == null) {\r
+            SharedPreferences.Editor editor = PreferenceManager\r
+                    .getDefaultSharedPreferences(this).edit();\r
+            editor.putString("select_oc_account", accountName);\r
+            editor.commit();\r
+        }\r
+\r
+        /// prepare result to return to the Authenticator\r
+        //  TODO check again what the Authenticator makes with it; probably has the same effect as addAccountExplicitly, but it's not well done\r
+        final Intent intent = new Intent();       \r
+        intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE,    AccountAuthenticator.ACCOUNT_TYPE);\r
+        intent.putExtra(AccountManager.KEY_ACCOUNT_NAME,    mAccount.name);\r
+        if (!isOAuth)\r
+            intent.putExtra(AccountManager.KEY_AUTHTOKEN,   AccountAuthenticator.ACCOUNT_TYPE); // TODO check this; not sure it's right; maybe\r
+        intent.putExtra(AccountManager.KEY_USERDATA,        username);\r
+        if (isOAuth) {\r
+            mAccountMgr.setAuthToken(mAccount, AccountAuthenticator.AUTH_TOKEN_TYPE_ACCESS_TOKEN, mOAuthAccessToken);\r
+        }\r
+        /// add user data to the new account; TODO probably can be done in the last parameter addAccountExplicitly, or in KEY_USERDATA\r
+        mAccountMgr.setUserData(mAccount, AccountAuthenticator.KEY_OC_VERSION,    mDiscoveredVersion.toString());\r
+        mAccountMgr.setUserData(mAccount, AccountAuthenticator.KEY_OC_BASE_URL,   mHostBaseUrl);\r
+        if (isOAuth)\r
+            mAccountMgr.setUserData(mAccount, AccountAuthenticator.KEY_SUPPORTS_OAUTH2, "TRUE");  // TODO this flag should be unnecessary\r
+    \r
+        setAccountAuthenticatorResult(intent.getExtras());\r
+        setResult(RESULT_OK, intent);\r
+        \r
+        /// immediately request for the synchronization of the new account\r
+        Bundle bundle = new Bundle();\r
+        bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);\r
+        ContentResolver.requestSync(mAccount, AccountAuthenticator.AUTHORITY, bundle);\r
+    }\r
+\r
+\r
+    /**\r
+     * {@inheritDoc}\r
+     * \r
+     * Necessary to update the contents of the SSL Dialog\r
+     * \r
+     * TODO move to some common place for all possible untrusted SSL failures\r
+     */\r
+    @Override\r
+    protected void onPrepareDialog(int id, Dialog dialog, Bundle args) {\r
+        switch (id) {\r
+        case DIALOG_LOGIN_PROGRESS:\r
+        case DIALOG_CERT_NOT_SAVED:\r
+        case DIALOG_OAUTH2_LOGIN_PROGRESS:\r
+            break;\r
+        case DIALOG_SSL_VALIDATOR: {\r
+            ((SslValidatorDialog)dialog).updateResult(mLastSslUntrustedServerResult);\r
+            break;\r
+        }\r
+        default:\r
+            Log_OC.e(TAG, "Incorrect dialog called with id = " + id);\r
+        }\r
+    }\r
+\r
+    \r
+    /**\r
+     * {@inheritDoc}\r
+     */\r
+    @Override\r
+    protected Dialog onCreateDialog(int id) {\r
+        Dialog dialog = null;\r
+        switch (id) {\r
+        case DIALOG_LOGIN_PROGRESS: {\r
+            /// simple progress dialog\r
+            ProgressDialog working_dialog = new ProgressDialog(this);\r
+            working_dialog.setMessage(getResources().getString(R.string.auth_trying_to_login));\r
+            working_dialog.setIndeterminate(true);\r
+            working_dialog.setCancelable(true);\r
+            working_dialog\r
+                    .setOnCancelListener(new DialogInterface.OnCancelListener() {\r
+                        @Override\r
+                        public void onCancel(DialogInterface dialog) {\r
+                            /// TODO study if this is enough\r
+                            Log_OC.i(TAG, "Login canceled");\r
+                            if (mOperationThread != null) {\r
+                                mOperationThread.interrupt();\r
+                                finish();\r
+                            }\r
+                        }\r
+                    });\r
+            dialog = working_dialog;\r
+            break;\r
+        }\r
+        case DIALOG_OAUTH2_LOGIN_PROGRESS: {\r
+            ProgressDialog working_dialog = new ProgressDialog(this);\r
+            working_dialog.setMessage(String.format("Getting authorization")); \r
+            working_dialog.setIndeterminate(true);\r
+            working_dialog.setCancelable(true);\r
+            working_dialog\r
+            .setOnCancelListener(new DialogInterface.OnCancelListener() {\r
+                @Override\r
+                public void onCancel(DialogInterface dialog) {\r
+                    Log_OC.i(TAG, "Login canceled");\r
+                    finish();\r
+                }\r
+            });\r
+            dialog = working_dialog;\r
+            break;\r
+        }\r
+        case DIALOG_SSL_VALIDATOR: {\r
+            /// TODO start to use new dialog interface, at least for this (it is a FragmentDialog already)\r
+            dialog = SslValidatorDialog.newInstance(this, mLastSslUntrustedServerResult, this);\r
+            break;\r
+        }\r
+        case DIALOG_CERT_NOT_SAVED: {\r
+            AlertDialog.Builder builder = new AlertDialog.Builder(this);\r
+            builder.setMessage(getResources().getString(R.string.ssl_validator_not_saved));\r
+            builder.setCancelable(false);\r
+            builder.setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() {\r
+                    @Override\r
+                    public void onClick(DialogInterface dialog, int which) {\r
+                        dialog.dismiss();\r
+                    };\r
+                });\r
+            dialog = builder.create();\r
+            break;\r
+        }\r
+        default:\r
+            Log_OC.e(TAG, "Incorrect dialog called with id = " + id);\r
+        }\r
+        return dialog;\r
+    }\r
+\r
+    \r
+    /**\r
+     * Starts and activity to open the 'new account' page in the ownCloud web site\r
+     * \r
+     * @param view      'Account register' button\r
+     */\r
+    public void onRegisterClick(View view) {\r
+        Intent register = new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.url_account_register)));\r
+        setResult(RESULT_CANCELED);\r
+        startActivity(register);\r
+    }\r
+\r
+    \r
+    /**\r
+     * Updates the content and visibility state of the icon and text associated\r
+     * to the last check on the ownCloud server.\r
+     */\r
+    private void updateConnStatus() {\r
+        ImageView iv = (ImageView) findViewById(R.id.action_indicator);\r
+        TextView tv = (TextView) findViewById(R.id.status_text);\r
+\r
+        if (mStatusIcon == 0 && mStatusText == 0) {\r
+            iv.setVisibility(View.INVISIBLE);\r
+            tv.setVisibility(View.INVISIBLE);\r
+        } else {\r
+            iv.setImageResource(mStatusIcon);\r
+            tv.setText(mStatusText);\r
+            iv.setVisibility(View.VISIBLE);\r
+            tv.setVisibility(View.VISIBLE);\r
+        }\r
+    }\r
+    \r
+    \r
+    /**\r
+     * Updates the content and visibility state of the icon and text associated\r
+     * to the interactions with the OAuth authorization server.\r
+     */\r
+    private void updateAuthStatus() {\r
+        if (mStatusIcon == 0 && mStatusText == 0) {\r
+            mAuthStatusLayout.setVisibility(View.INVISIBLE);\r
+        } else {\r
+            mAuthStatusLayout.setText(mStatusText);\r
+            mAuthStatusLayout.setCompoundDrawablesWithIntrinsicBounds(mStatusIcon, 0, 0, 0);\r
+            mAuthStatusLayout.setVisibility(View.VISIBLE);\r
+        }\r
+    }     \r
+\r
+    \r
+    /**\r
+     * Called when the refresh button in the input field for ownCloud host is clicked.\r
+     * \r
+     * Performs a new check on the URL in the input field.\r
+     * \r
+     * @param view      Refresh 'button'\r
+     */\r
+    public void onRefreshClick(View view) {\r
+        onFocusChange(mRefreshButton, false);\r
+    }\r
+    \r
+    \r
+    /**\r
+     * Called when the eye icon in the password field is clicked.\r
+     * \r
+     * Toggles the visibility of the password in the field. \r
+     * \r
+     * @param view      'View password' 'button'\r
+     */\r
+    public void onViewPasswordClick(View view) {\r
+        int selectionStart = mPasswordInput.getSelectionStart();\r
+        int selectionEnd = mPasswordInput.getSelectionEnd();\r
+        int input_type = mPasswordInput.getInputType();\r
+        if ((input_type & InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) == InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) {\r
+            input_type = InputType.TYPE_CLASS_TEXT\r
+                    | InputType.TYPE_TEXT_VARIATION_PASSWORD;\r
+        } else {\r
+            input_type = InputType.TYPE_CLASS_TEXT\r
+                    | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD;\r
+        }\r
+        mPasswordInput.setInputType(input_type);\r
+        mPasswordInput.setSelection(selectionStart, selectionEnd);\r
+    }    \r
+    \r
+    \r
+    /**\r
+     * Called when the checkbox for OAuth authorization is clicked.\r
+     * \r
+     * Hides or shows the input fields for user & password. \r
+     * \r
+     * @param view      'View password' 'button'\r
+     */\r
+    public void onCheckClick(View view) {\r
+        CheckBox oAuth2Check = (CheckBox)view;      \r
+        changeViewByOAuth2Check(oAuth2Check.isChecked());\r
+\r
+    }\r
+    \r
+    /**\r
+     * Changes the visibility of input elements depending upon the kind of authorization\r
+     * chosen by the user: basic or OAuth\r
+     * \r
+     * @param checked       'True' when OAuth is selected.\r
+     */\r
+    public void changeViewByOAuth2Check(Boolean checked) {\r
+        \r
+        if (checked) {\r
+            mOAuthAuthEndpointText.setVisibility(View.VISIBLE);\r
+            mOAuthTokenEndpointText.setVisibility(View.VISIBLE);\r
+            mUsernameInput.setVisibility(View.GONE);\r
+            mPasswordInput.setVisibility(View.GONE);\r
+            mViewPasswordButton.setVisibility(View.GONE);\r
+        } else {\r
+            mOAuthAuthEndpointText.setVisibility(View.GONE);\r
+            mOAuthTokenEndpointText.setVisibility(View.GONE);\r
+            mUsernameInput.setVisibility(View.VISIBLE);\r
+            mPasswordInput.setVisibility(View.VISIBLE);\r
+            mViewPasswordButton.setVisibility(View.INVISIBLE);\r
+        }     \r
+\r
+    }    \r
+    \r
+    /**\r
+     * Called from SslValidatorDialog when a new server certificate was correctly saved.\r
+     */\r
+    public void onSavedCertificate() {\r
+        mOperationThread = mOcServerChkOperation.retry(this, mHandler);                \r
+    }\r
+\r
+    /**\r
+     * Called from SslValidatorDialog when a new server certificate could not be saved \r
+     * when the user requested it.\r
+     */\r
+    @Override\r
+    public void onFailedSavingCertificate() {\r
+        showDialog(DIALOG_CERT_NOT_SAVED);\r
+    }\r
+\r
+}\r
diff --git a/src/com/owncloud/android/authentication/OAuth2Constants.java b/src/com/owncloud/android/authentication/OAuth2Constants.java
new file mode 100644 (file)
index 0000000..f96b627
--- /dev/null
@@ -0,0 +1,53 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2012-2013 ownCloud Inc.
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License version 2,
+ *   as published by the Free Software Foundation.
+ *
+ *   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 com.owncloud.android.authentication;
+
+/** 
+ * Constant values for OAuth 2 protocol.
+ * 
+ * Includes required and optional parameter NAMES used in the 'authorization code' grant type.
+ *  
+ * @author David A. Velasco
+ */
+
+public class OAuth2Constants {
+    
+    /// Parameters to send to the Authorization Endpoint
+    public static final String KEY_RESPONSE_TYPE = "response_type";
+    public static final String KEY_REDIRECT_URI = "redirect_uri";
+    public static final String KEY_CLIENT_ID = "client_id";
+    public static final String KEY_SCOPE = "scope";
+    public static final String KEY_STATE = "state"; 
+    
+    /// Additional parameters to send to the Token Endpoint
+    public static final String KEY_GRANT_TYPE = "grant_type";
+    public static final String KEY_CODE = "code";
+    
+    /// Parameters received in an OK response from the Token Endpoint 
+    public static final String KEY_ACCESS_TOKEN = "access_token";
+    public static final String KEY_TOKEN_TYPE = "token_type";
+    public static final String KEY_EXPIRES_IN = "expires_in";
+    public static final String KEY_REFRESH_TOKEN = "refresh_token";
+    
+    /// Parameters in an ERROR response
+    public static final String KEY_ERROR = "error";
+    public static final String KEY_ERROR_DESCRIPTION = "error_description";
+    public static final String KEY_ERROR_URI = "error_uri";
+    public static final String VALUE_ERROR_ACCESS_DENIED = "access_denied";
+    
+}
diff --git a/src/com/owncloud/android/authenticator/AccountAuthenticator.java b/src/com/owncloud/android/authenticator/AccountAuthenticator.java
deleted file mode 100644 (file)
index 2cbc9d3..0000000
+++ /dev/null
@@ -1,282 +0,0 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012  Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License version 2,
- *   as published by the Free Software Foundation.
- *
- *   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 com.owncloud.android.authenticator;
-
-import com.owncloud.android.Log_OC;
-import com.owncloud.android.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 {
-    /**
-     * Is used by android system to assign accounts to authenticators. Should be
-     * used by application and all extensions.
-     */
-    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";
-    /**
-     * Value under this key should handle path to webdav php script. Will be
-     * removed and usage should be replaced by combining
-     * {@link com.owncloud.android.authenticator.AuthenticatorActivity.KEY_OC_BASE_URL} and
-     * {@link com.owncloud.android.utils.OwnCloudVersion}
-     * 
-     * @deprecated
-     */
-    public static final String KEY_OC_URL = "oc_url";
-    /**
-     * Version should be 3 numbers separated by dot so it can be parsed by
-     * {@link com.owncloud.android.utils.OwnCloudVersion}
-     */
-    public static final String KEY_OC_VERSION = "oc_version";
-    /**
-     * Base url should point to owncloud installation without trailing / ie:
-     * http://server/path or https://owncloud.server
-     */
-    public static final String KEY_OC_BASE_URL = "oc_base_url";
-
-    private static final String TAG = "AccountAuthenticator";
-    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_OC.i(TAG, "Adding account with type " + accountType
-                + " and auth token " + authTokenType);
-        try {
-            validateAccountType(accountType);
-        } catch (AuthenticatorException e) {
-            Log_OC.e(TAG, "Failed to validate account type " + accountType + ": "
-                    + e.getMessage());
-            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);
-        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) {
-            Log_OC.e(TAG, "Failed to validate account type " + account.type + ": "
-                    + e.getMessage());
-            e.printStackTrace();
-            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) {
-        return null;
-    }
-
-    @Override
-    public Bundle getAuthToken(AccountAuthenticatorResponse response,
-            Account account, String authTokenType, Bundle options)
-            throws NetworkErrorException {
-        try {
-            validateAccountType(account.type);
-            validateAuthTokenType(authTokenType);
-        } catch (AuthenticatorException e) {
-            Log_OC.e(TAG, "Failed to validate account type " + account.type + ": "
-                    + e.getMessage());
-            e.printStackTrace();
-            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, true);
-        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();
-        }
-    }
-
-    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;
-
-    }
-}
diff --git a/src/com/owncloud/android/authenticator/AccountAuthenticatorService.java b/src/com/owncloud/android/authenticator/AccountAuthenticatorService.java
deleted file mode 100644 (file)
index 220f7f4..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/* ownCloud Android client application
- *   Copyright (C) 2011  Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License version 2,
- *   as published by the Free Software Foundation.
- *
- *   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 com.owncloud.android.authenticator;
-
-import android.app.Service;
-import android.content.Intent;
-import android.os.IBinder;
-
-public class AccountAuthenticatorService extends Service {
-
-    private AccountAuthenticator mAuthenticator;
-    static final public String ACCOUNT_TYPE = "owncloud";
-
-    @Override
-    public void onCreate() {
-        super.onCreate();
-        mAuthenticator = new AccountAuthenticator(this);
-    }
-
-    @Override
-    public IBinder onBind(Intent intent) {
-        return mAuthenticator.getIBinder();
-    }
-
-}
diff --git a/src/com/owncloud/android/authenticator/AuthenticationRunnable.java b/src/com/owncloud/android/authenticator/AuthenticationRunnable.java
deleted file mode 100644 (file)
index 2df4427..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012 Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License version 2,
- *   as published by the Free Software Foundation.
- *
- *   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 com.owncloud.android.authenticator;
-
-import java.net.URL;
-
-import org.apache.commons.httpclient.HttpStatus;
-
-import com.owncloud.android.R;
-import com.owncloud.android.network.OwnCloudClientUtils;
-
-import eu.alefzero.webdav.WebdavClient;
-
-import android.content.Context;
-import android.net.Uri;
-import android.os.Handler;
-
-public class AuthenticationRunnable implements Runnable {
-
-    private OnAuthenticationResultListener mListener;
-    private Handler mHandler;
-    private URL mUrl;
-    private String mUsername;
-    private String mPassword;
-    private Context mContext;
-
-    public AuthenticationRunnable(URL url, String username, String password, Context context) {
-        mListener = null;
-        mUrl = url;
-        mUsername = username;
-        mPassword = password;
-        mContext = context;
-    }
-
-    public void setOnAuthenticationResultListener(
-            OnAuthenticationResultListener listener, Handler handler) {
-        mListener = listener;
-        mHandler = handler;
-    }
-
-    @Override
-    public void run() {
-        Uri uri;
-        uri = Uri.parse(mUrl.toString());
-        WebdavClient wdc = OwnCloudClientUtils.createOwnCloudClient(uri, mUsername, mPassword, mContext);
-        int login_result = wdc.tryToLogin();
-        switch (login_result) {
-        case HttpStatus.SC_OK:
-            postResult(true, uri.toString());
-            break;
-        case HttpStatus.SC_UNAUTHORIZED:
-            postResult(false, mContext.getString(R.string.auth_unauthorized));
-            break;
-        case HttpStatus.SC_NOT_FOUND:
-            postResult(false, mContext.getString(R.string.auth_not_found));
-            break;
-        default:
-            postResult(false, String.format(mContext.getString(R.string.auth_internal), login_result));
-        }
-    }
-
-    private void postResult(final boolean success, final String message) {
-        if (mHandler != null && mListener != null) {
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    mListener.onAuthenticationResult(success, message);
-                }
-            });
-        }
-    }
-}
diff --git a/src/com/owncloud/android/authenticator/OnAuthenticationResultListener.java b/src/com/owncloud/android/authenticator/OnAuthenticationResultListener.java
deleted file mode 100644 (file)
index 66dc018..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012 Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License version 2,
- *   as published by the Free Software Foundation.
- *
- *   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 com.owncloud.android.authenticator;
-
-public interface OnAuthenticationResultListener {
-
-    public void onAuthenticationResult(boolean success, String message);
-
-}
diff --git a/src/com/owncloud/android/authenticator/OnConnectCheckListener.java b/src/com/owncloud/android/authenticator/OnConnectCheckListener.java
deleted file mode 100644 (file)
index 1aa3dc5..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012 Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License version 2,
- *   as published by the Free Software Foundation.
- *
- *   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 com.owncloud.android.authenticator;
-
-public interface OnConnectCheckListener {
-
-    enum ResultType {
-        OK_SSL, OK_NO_SSL, SSL_INIT_ERROR, HOST_NOT_AVAILABLE, TIMEOUT, NO_NETWORK_CONNECTION, INCORRECT_ADDRESS, INSTANCE_NOT_CONFIGURED, FILE_NOT_FOUND, UNKNOWN_ERROR, WRONG_CONNECTION,  SSL_UNVERIFIED_SERVER, BAD_OC_VERSION
-    }
-
-    public void onConnectionCheckResult(ResultType type);
-
-}
index 434bc47..1b0f083 100644 (file)
@@ -40,7 +40,6 @@ import android.content.OperationApplicationException;
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.RemoteException;
-import android.util.Log;
 
 public class FileDataStorageManager implements DataStorageManager {
 
index e3cfe4f..889d1db 100644 (file)
@@ -24,7 +24,6 @@ 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
index ebe9450..15db896 100644 (file)
@@ -23,7 +23,6 @@ import com.owncloud.android.R;
 import android.content.Intent;
 import android.os.Bundle;
 import android.support.v4.app.DialogFragment;
-import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
index 2a94418..2f7290e 100644 (file)
@@ -35,7 +35,6 @@ import android.R;
 import android.app.ListActivity;
 import android.os.Bundle;
 import android.os.Handler;
-import android.util.Log;
 import android.widget.SimpleAdapter;
 
 public class ExtensionsListActivity extends ListActivity {
index 97d0404..8a8c430 100644 (file)
@@ -24,7 +24,6 @@ import com.owncloud.android.files.services.FileObserverService;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
-import android.util.Log;
 
 public class BootupBroadcastReceiver extends BroadcastReceiver {
 
index 74d20f0..c9272b6 100644 (file)
@@ -20,6 +20,11 @@ package com.owncloud.android.files;
 
 import java.io.File;
 
+import com.owncloud.android.AccountUtils;
+import com.owncloud.android.authentication.AccountAuthenticator;
+import com.owncloud.android.db.DbHandler;
+import com.owncloud.android.files.services.FileUploader;
+
 import android.accounts.Account;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -32,11 +37,7 @@ import android.preference.PreferenceManager;
 import android.provider.MediaStore.Images.Media;
 import android.webkit.MimeTypeMap;
 
-import com.owncloud.android.AccountUtils;
 import com.owncloud.android.Log_OC;
-import com.owncloud.android.authenticator.AccountAuthenticator;
-import com.owncloud.android.db.DbHandler;
-import com.owncloud.android.files.services.FileUploader;
 import com.owncloud.android.utils.FileStorageUtils;
 
 public class InstantUploadBroadcastReceiver extends BroadcastReceiver {
index 10dbdfc..2ea90c9 100644 (file)
@@ -23,19 +23,16 @@ import java.io.File;
 import com.owncloud.android.Log_OC;
 import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
-import com.owncloud.android.network.OwnCloudClientUtils;
 import com.owncloud.android.operations.RemoteOperationResult;
 import com.owncloud.android.operations.SynchronizeFileOperation;
 import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
 import com.owncloud.android.ui.activity.ConflictsResolveActivity;
 
-import eu.alefzero.webdav.WebdavClient;
 
 import android.accounts.Account;
 import android.content.Context;
 import android.content.Intent;
 import android.os.FileObserver;
-import android.util.Log;
 
 public class OwnCloudFileObserver extends FileObserver {
 
@@ -78,7 +75,6 @@ public class OwnCloudFileObserver extends FileObserver {
                          mPath);
             return;
         }
-        WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(mOCAccount, mContext);
         FileDataStorageManager storageManager = new FileDataStorageManager(mOCAccount, mContext.getContentResolver());
         OCFile file = storageManager.getFileByLocalPath(mPath);     // a fresh object is needed; many things could have occurred to the file since it was registered to observe
                                                                     // again, assuming that local files are linked to a remote file AT MOST, SOMETHING TO BE DONE; 
@@ -89,7 +85,7 @@ public class OwnCloudFileObserver extends FileObserver {
                                                                     true, 
                                                                     true, 
                                                                     mContext);
-        RemoteOperationResult result = sfo.execute(wc);
+        RemoteOperationResult result = sfo.execute(mOCAccount, mContext);
         if (result.getCode() == ResultCode.SYNC_CONFLICT) {
             // ISSUE 5: if the user is not running the app (this is a service!), this can be very intrusive; a notification should be preferred
             Intent i = new Intent(mContext, ConflictsResolveActivity.class);
index 8368603..cf88ce0 100644 (file)
@@ -19,6 +19,7 @@
 package com.owncloud.android.files.services;
 
 import java.io.File;
+import java.io.IOException;
 import java.util.AbstractList;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -27,6 +28,7 @@ import java.util.Vector;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
+import com.owncloud.android.authentication.AuthenticatorActivity;
 import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
 import eu.alefzero.webdav.OnDatatransferProgressListener;
@@ -34,12 +36,14 @@ import eu.alefzero.webdav.OnDatatransferProgressListener;
 import com.owncloud.android.network.OwnCloudClientUtils;
 import com.owncloud.android.operations.DownloadFileOperation;
 import com.owncloud.android.operations.RemoteOperationResult;
+import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
 import com.owncloud.android.ui.activity.FileDetailActivity;
 import com.owncloud.android.ui.fragment.FileDetailFragment;
 import com.owncloud.android.ui.preview.PreviewImageActivity;
 import com.owncloud.android.ui.preview.PreviewImageFragment;
 
 import android.accounts.Account;
+import android.accounts.AccountsException;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
@@ -113,7 +117,6 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis
         mBinder = new FileDownloaderBinder();
     }
 
-    
     /**
      * Entry point to add one or several files to the queue of downloads.
      * 
@@ -256,7 +259,6 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis
         }
         
         
-        
         /**
          * Removes a listener interested in the progress of the download for a concrete file.
          * 
@@ -321,7 +323,6 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis
         }
     }
     
-    
 
     /**
      * Core download method: requests a file to download and stores it.
@@ -338,21 +339,28 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis
             
             notifyDownloadStart(mCurrentDownload);
 
-            /// prepare client object to send the request to the ownCloud server
-            if (mDownloadClient == null || !mLastAccount.equals(mCurrentDownload.getAccount())) {
-                mLastAccount = mCurrentDownload.getAccount();
-                mStorageManager = new FileDataStorageManager(mLastAccount, getContentResolver());
-                mDownloadClient = OwnCloudClientUtils.createOwnCloudClient(mLastAccount, getApplicationContext());
-            }
-
-            /// perform the download
             RemoteOperationResult downloadResult = null;
             try {
+                /// prepare client object to send the request to the ownCloud server
+                if (mDownloadClient == null || !mLastAccount.equals(mCurrentDownload.getAccount())) {
+                    mLastAccount = mCurrentDownload.getAccount();
+                    mStorageManager = new FileDataStorageManager(mLastAccount, getContentResolver());
+                    mDownloadClient = OwnCloudClientUtils.createOwnCloudClient(mLastAccount, getApplicationContext());
+                }
+
+                /// perform the download
                 downloadResult = mCurrentDownload.execute(mDownloadClient);
                 if (downloadResult.isSuccess()) {
                     saveDownloadedFile();
                 }
             
+            } catch (AccountsException e) {
+                Log_OC.e(TAG, "Error while trying to get autorization for " + mLastAccount.name, e);
+                downloadResult = new RemoteOperationResult(e);
+            } catch (IOException e) {
+                Log_OC.e(TAG, "Error while trying to get autorization for " + mLastAccount.name, e);
+                downloadResult = new RemoteOperationResult(e);
+                
             } finally {
                 synchronized(mPendingDownloads) {
                     mPendingDownloads.remove(downloadKey);
@@ -455,23 +463,41 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis
             int contentId = (downloadResult.isSuccess()) ? R.string.downloader_download_succeeded_content : R.string.downloader_download_failed_content;
             Notification finalNotification = new Notification(R.drawable.icon, getString(tickerId), System.currentTimeMillis());
             finalNotification.flags |= Notification.FLAG_AUTO_CANCEL;
-            Intent showDetailsIntent = null;
-            if (downloadResult.isSuccess()) {
-                if (PreviewImageFragment.canBePreviewed(download.getFile())) {
-                    showDetailsIntent = new Intent(this, PreviewImageActivity.class);
-                } else {
-                    showDetailsIntent = new Intent(this, FileDetailActivity.class);
-                }
-                showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, download.getFile());
-                showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, download.getAccount());
-                showDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+            boolean needsToUpdateCredentials = (downloadResult.getCode() == ResultCode.UNAUTHORIZED);
+            if (needsToUpdateCredentials) {
+                // let the user update credentials with one click
+                Intent updateAccountCredentials = new Intent(this, AuthenticatorActivity.class);
+                updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, download.getAccount());
+                updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACTION, AuthenticatorActivity.ACTION_UPDATE_TOKEN);
+                updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+                updateAccountCredentials.addFlags(Intent.FLAG_FROM_BACKGROUND);
+                finalNotification.contentIntent = PendingIntent.getActivity(this, (int)System.currentTimeMillis(), updateAccountCredentials, PendingIntent.FLAG_ONE_SHOT);
+                finalNotification.setLatestEventInfo(   getApplicationContext(), 
+                                                        getString(tickerId), 
+                                                        String.format(getString(contentId), new File(download.getSavePath()).getName()),
+                                                        finalNotification.contentIntent);
+                mDownloadClient = null;   // grant that future retries on the same account will get the fresh credentials
                 
             } else {
-                // TODO put something smart in showDetailsIntent
-                showDetailsIntent = new Intent();
+                Intent showDetailsIntent = null;
+                if (downloadResult.isSuccess()) {
+                    if (PreviewImageFragment.canBePreviewed(download.getFile())) {
+                        showDetailsIntent = new Intent(this, PreviewImageActivity.class);
+                    } else {
+                        showDetailsIntent = new Intent(this, FileDetailActivity.class);
+                    }
+                    showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, download.getFile());
+                    showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, download.getAccount());
+                    showDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+                    
+                } else {
+                    // TODO put something smart in showDetailsIntent
+                    showDetailsIntent = new Intent();
+                }
+                finalNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(), (int)System.currentTimeMillis(), showDetailsIntent, 0);
+                finalNotification.setLatestEventInfo(getApplicationContext(), getString(tickerId), String.format(getString(contentId), new File(download.getSavePath()).getName()), finalNotification.contentIntent);
             }
-            finalNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(), (int)System.currentTimeMillis(), showDetailsIntent, 0);
-            finalNotification.setLatestEventInfo(getApplicationContext(), getString(tickerId), String.format(getString(contentId), new File(download.getSavePath()).getName()), finalNotification.contentIntent);
             mNotificationManager.notify(tickerId, finalNotification);
         }
     }
index a01446a..fd1412c 100644 (file)
@@ -40,7 +40,6 @@ import android.content.IntentFilter;
 import android.database.Cursor;
 import android.os.Binder;
 import android.os.IBinder;
-import android.util.Log;
 
 public class FileObserverService extends Service {
 
diff --git a/src/com/owncloud/android/files/services/FileOperation.java b/src/com/owncloud/android/files/services/FileOperation.java
deleted file mode 100644 (file)
index d48a185..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012  Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License version 2,
- *   as published by the Free Software Foundation.
- *
- *   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 com.owncloud.android.files.services;
-
-import java.io.File;
-
-import com.owncloud.android.AccountUtils;
-import com.owncloud.android.datamodel.OCFile;
-import com.owncloud.android.network.OwnCloudClientUtils;
-
-import android.accounts.Account;
-import android.content.Context;
-import eu.alefzero.webdav.WebdavClient;
-
-public class FileOperation {
-
-    Context mContext;
-    
-    public FileOperation(Context contex){
-        this.mContext = contex;
-    }
-    
-    /**
-     * Deletes a file from ownCloud - locally and remote.
-     * @param file The file to delete
-     * @return True on success, otherwise false
-     */
-    public boolean delete(OCFile file){
-        
-        Account account = AccountUtils.getCurrentOwnCloudAccount(mContext);
-        WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(account, mContext);
-        if(client.deleteFile(file.getRemotePath())){
-            File localFile = new File(file.getStoragePath());
-            return localFile.delete();
-        }
-        
-        return false;
-    }
-    
-}
index a3c76eb..7866098 100644 (file)
@@ -19,6 +19,7 @@
 package com.owncloud.android.files.services;
 
 import java.io.File;
+import java.io.IOException;
 import java.util.AbstractList;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -31,8 +32,29 @@ import org.apache.http.HttpStatus;
 import org.apache.jackrabbit.webdav.MultiStatus;
 import org.apache.jackrabbit.webdav.client.methods.PropFindMethod;
 
+import com.owncloud.android.authentication.AccountAuthenticator;
+import com.owncloud.android.authentication.AuthenticatorActivity;
+import com.owncloud.android.datamodel.FileDataStorageManager;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.operations.ChunkedUploadFileOperation;
+import com.owncloud.android.operations.CreateFolderOperation;
+import com.owncloud.android.operations.RemoteOperation;
+import com.owncloud.android.operations.RemoteOperationResult;
+import com.owncloud.android.operations.UploadFileOperation;
+import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
+import com.owncloud.android.ui.activity.FileDetailActivity;
+import com.owncloud.android.ui.fragment.FileDetailFragment;
+import com.owncloud.android.utils.OwnCloudVersion;
+
+import eu.alefzero.webdav.OnDatatransferProgressListener;
+import eu.alefzero.webdav.WebdavEntry;
+import eu.alefzero.webdav.WebdavUtils;
+
+import com.owncloud.android.network.OwnCloudClientUtils;
+
 import android.accounts.Account;
 import android.accounts.AccountManager;
+import android.accounts.AccountsException;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
@@ -47,32 +69,17 @@ import android.os.Message;
 import android.os.Process;
 import android.webkit.MimeTypeMap;
 import android.widget.RemoteViews;
-import android.widget.Toast;
 
 import com.owncloud.android.Log_OC;
 import com.owncloud.android.R;
-import com.owncloud.android.authenticator.AccountAuthenticator;
-import com.owncloud.android.datamodel.FileDataStorageManager;
-import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.db.DbHandler;
-import com.owncloud.android.network.OwnCloudClientUtils;
-import com.owncloud.android.operations.ChunkedUploadFileOperation;
-import com.owncloud.android.operations.RemoteOperationResult;
-import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
-import com.owncloud.android.operations.UploadFileOperation;
 import com.owncloud.android.ui.activity.FailedUploadActivity;
-import com.owncloud.android.ui.activity.FileDetailActivity;
 import com.owncloud.android.ui.activity.InstantUploadActivity;
-import com.owncloud.android.ui.fragment.FileDetailFragment;
 import com.owncloud.android.ui.preview.PreviewImageActivity;
 import com.owncloud.android.ui.preview.PreviewImageFragment;
 import com.owncloud.android.utils.FileStorageUtils;
-import com.owncloud.android.utils.OwnCloudVersion;
 
-import eu.alefzero.webdav.OnDatatransferProgressListener;
 import eu.alefzero.webdav.WebdavClient;
-import eu.alefzero.webdav.WebdavEntry;
-import eu.alefzero.webdav.WebdavUtils;
 
 public class FileUploader extends Service implements OnDatatransferProgressListener {
 
@@ -490,37 +497,48 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
 
             notifyUploadStart(mCurrentUpload);
 
-            // / prepare client object to send requests to the ownCloud server
-            if (mUploadClient == null || !mLastAccount.equals(mCurrentUpload.getAccount())) {
-                mLastAccount = mCurrentUpload.getAccount();
-                mStorageManager = new FileDataStorageManager(mLastAccount, getContentResolver());
-                mUploadClient = OwnCloudClientUtils.createOwnCloudClient(mLastAccount, getApplicationContext());
-            }
-
-            // / create remote folder for instant uploads
-            if (mCurrentUpload.isRemoteFolderToBeCreated()) {
-                mUploadClient.createDirectory(FileStorageUtils.getInstantUploadFilePath(this, ""));
-                // ignoring result fail could just mean that it already exists,
-                // but local database is not synchronized the upload will be
-                // tried anyway
-            }
-
-            // / perform the upload
             RemoteOperationResult uploadResult = null;
+            
             try {
+                /// prepare client object to send requests to the ownCloud server
+                if (mUploadClient == null || !mLastAccount.equals(mCurrentUpload.getAccount())) {
+                    mLastAccount = mCurrentUpload.getAccount();
+                    mStorageManager = new FileDataStorageManager(mLastAccount, getContentResolver());
+                    mUploadClient = OwnCloudClientUtils.createOwnCloudClient(mLastAccount, getApplicationContext());
+                }
+            
+                /// create remote folder for instant uploads
+                if (mCurrentUpload.isRemoteFolderToBeCreated()) {
+                    RemoteOperation operation = new CreateFolderOperation(  FileStorageUtils.getInstantUploadFilePath(this, ""), 
+                                                                            mStorageManager.getFileByPath(OCFile.PATH_SEPARATOR).getFileId(), // TODO generalize this : INSTANT_UPLOAD_DIR could not be a child of root
+                                                                            mStorageManager);
+                    operation.execute(mUploadClient);      // ignoring result; fail could just mean that it already exists, but local database is not synchronized; the upload will be tried anyway
+                }
+
+            
+                /// perform the upload
                 uploadResult = mCurrentUpload.execute(mUploadClient);
                 if (uploadResult.isSuccess()) {
                     saveUploadedFile();
                 }
-
+                
+            } catch (AccountsException e) {
+                Log_OC.e(TAG, "Error while trying to get autorization for " + mLastAccount.name, e);
+                uploadResult = new RemoteOperationResult(e);
+                
+            } catch (IOException e) {
+                Log_OC.e(TAG, "Error while trying to get autorization for " + mLastAccount.name, e);
+                uploadResult = new RemoteOperationResult(e);
+                
             } finally {
                 synchronized (mPendingUploads) {
                     mPendingUploads.remove(uploadKey);
                     Log_OC.i(TAG, "Remove CurrentUploadItem from pending upload Item Map.");
                 }
             }
-
-            // notify result
+            
+            /// notify result
+            
             notifyUploadResult(uploadResult, mCurrentUpload);
             sendFinalBroadcast(mCurrentUpload, uploadResult);
 
@@ -775,7 +793,21 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
             Notification finalNotification = new Notification(R.drawable.icon,
                     getString(R.string.uploader_upload_failed_ticker), System.currentTimeMillis());
             finalNotification.flags |= Notification.FLAG_AUTO_CANCEL;
-
+            if (uploadResult.getCode() == ResultCode.UNAUTHORIZED) {
+                // let the user update credentials with one click
+                Intent updateAccountCredentials = new Intent(this, AuthenticatorActivity.class);
+                updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, upload.getAccount());
+                updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACTION, AuthenticatorActivity.ACTION_UPDATE_TOKEN);
+                updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+                updateAccountCredentials.addFlags(Intent.FLAG_FROM_BACKGROUND);
+                finalNotification.contentIntent = PendingIntent.getActivity(this, (int)System.currentTimeMillis(), updateAccountCredentials, PendingIntent.FLAG_ONE_SHOT);
+                mUploadClient = null;   // grant that future retries on the same account will get the fresh credentials
+            } else {
+                // TODO put something smart in the contentIntent below
+                finalNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(), (int)System.currentTimeMillis(), new Intent(), 0);
+            }
+            
             String content = null;
             if (uploadResult.getCode() == ResultCode.LOCAL_STORAGE_FULL
                     || uploadResult.getCode() == ResultCode.LOCAL_STORAGE_NOT_COPIED) {
index 6bbb9ee..a974c56 100644 (file)
@@ -26,7 +26,6 @@ import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.preference.PreferenceManager;
-import android.util.Log;
 
 public class LocationServiceLauncherReciever extends BroadcastReceiver {
 
index f2eab98..7fe2ee9 100644 (file)
@@ -27,7 +27,6 @@ import android.location.LocationManager;
 import android.location.LocationProvider;
 import android.os.Bundle;
 import android.preference.PreferenceManager;
-import android.util.Log;
 import android.widget.Toast;
 
 import com.owncloud.android.Log_OC;
index 3f1d8ae..da9a0ff 100644 (file)
@@ -41,8 +41,6 @@ import org.apache.http.conn.ssl.X509HostnameVerifier;
 
 import com.owncloud.android.Log_OC;
 
-import android.util.Log;
-
 /**
  * AdvancedSSLProtocolSocketFactory allows to create SSL {@link Socket}s with 
  * a custom SSLContext and an optional Hostname Verifier.
index 578da18..ad4feb3 100644 (file)
@@ -33,8 +33,6 @@ import javax.net.ssl.X509TrustManager;
 
 import com.owncloud.android.Log_OC;
 
-import android.util.Log;
-
 /**
  * @author David A. Velasco
  */
diff --git a/src/com/owncloud/android/network/BearerAuthScheme.java b/src/com/owncloud/android/network/BearerAuthScheme.java
new file mode 100644 (file)
index 0000000..a426734
--- /dev/null
@@ -0,0 +1,268 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2012  ownCloud Inc.
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License version 2,
+ *   as published by the Free Software Foundation.
+ *
+ *   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 com.owncloud.android.network;
+
+import java.util.Map;
+
+import org.apache.commons.httpclient.Credentials;
+import org.apache.commons.httpclient.HttpMethod;
+import org.apache.commons.httpclient.auth.AuthChallengeParser;
+import org.apache.commons.httpclient.auth.AuthScheme;
+import org.apache.commons.httpclient.auth.AuthenticationException;
+import org.apache.commons.httpclient.auth.InvalidCredentialsException;
+import org.apache.commons.httpclient.auth.MalformedChallengeException;
+
+import com.owncloud.android.Log_OC;
+
+/**
+ * Bearer authentication scheme as defined in RFC 6750.
+ * 
+ * @author David A. Velasco
+ */
+
+public class BearerAuthScheme implements AuthScheme /*extends RFC2617Scheme*/ {
+    
+    private static final String TAG = BearerAuthScheme.class.getSimpleName();
+
+    public static final String AUTH_POLICY = "Bearer";
+    
+    /** Whether the bearer authentication process is complete */
+    private boolean mComplete;
+    
+    /** Authentication parameter map */
+    private Map mParams = null;
+    
+    
+    /**
+     * Default constructor for the bearer authentication scheme.
+     */
+    public BearerAuthScheme() {
+        mComplete = false;
+    }
+
+    /**
+     * Constructor for the basic authentication scheme.
+     * 
+     * @param   challenge                       Authentication challenge
+     * 
+     * @throws  MalformedChallengeException     Thrown if the authentication challenge is malformed
+     * 
+     * @deprecated Use parameterless constructor and {@link AuthScheme#processChallenge(String)} method
+     */
+    public BearerAuthScheme(final String challenge) throws MalformedChallengeException {
+        processChallenge(challenge);
+        mComplete = true;
+    }
+
+    /**
+     * Returns textual designation of the bearer authentication scheme.
+     * 
+     * @return "Bearer"
+     */
+    public String getSchemeName() {
+        return "bearer";
+    }
+
+    /**
+     * Processes the Bearer challenge.
+     *  
+     * @param   challenge                   The challenge string
+     * 
+     * @throws MalformedChallengeException  Thrown if the authentication challenge is malformed
+     */
+    public void processChallenge(String challenge) throws MalformedChallengeException {
+        String s = AuthChallengeParser.extractScheme(challenge);
+        if (!s.equalsIgnoreCase(getSchemeName())) {
+            throw new MalformedChallengeException(
+              "Invalid " + getSchemeName() + " challenge: " + challenge); 
+        }
+        mParams = AuthChallengeParser.extractParams(challenge);
+        mComplete = true;
+    }
+
+    /**
+     * Tests if the Bearer authentication process has been completed.
+     * 
+     * @return 'true' if Bearer authorization has been processed, 'false' otherwise.
+     */
+    public boolean isComplete() {
+        return this.mComplete;
+    }
+
+    /**
+     * Produces bearer authorization string for the given set of 
+     * {@link Credentials}.
+     * 
+     * @param   credentials                     The set of credentials to be used for authentication
+     * @param   method                          Method name is ignored by the bearer authentication scheme
+     * @param   uri                             URI is ignored by the bearer authentication scheme
+     * @throws  InvalidCredentialsException     If authentication credentials are not valid or not applicable 
+     *                                          for this authentication scheme
+     * @throws  AuthenticationException         If authorization string cannot be generated due to an authentication failure
+     * @return  A bearer authorization string
+     * 
+     * @deprecated Use {@link #authenticate(Credentials, HttpMethod)}
+     */
+    public String authenticate(Credentials credentials, String method, String uri) throws AuthenticationException {
+        Log_OC.d(TAG, "enter BearerScheme.authenticate(Credentials, String, String)");
+
+        BearerCredentials bearer = null;
+        try {
+            bearer = (BearerCredentials) credentials;
+        } catch (ClassCastException e) {
+            throw new InvalidCredentialsException(
+             "Credentials cannot be used for bearer authentication: " 
+              + credentials.getClass().getName());
+        }
+        return BearerAuthScheme.authenticate(bearer);
+    }
+
+    
+    /**
+     * Returns 'false'. Bearer authentication scheme is request based.
+     * 
+     * @return 'false'.
+     */
+    public boolean isConnectionBased() {
+        return false;    
+    }
+
+    /**
+     * Produces bearer authorization string for the given set of {@link Credentials}.
+     * 
+     * @param   credentials                     The set of credentials to be used for authentication
+     * @param   method                          The method being authenticated
+     * @throws  InvalidCredentialsException     If authentication credentials are not valid or not applicable for this authentication 
+     *                                          scheme.
+     * @throws AuthenticationException         If authorization string cannot be generated due to an authentication failure.
+     * 
+     * @return a basic authorization string
+     */
+    public String authenticate(Credentials credentials, HttpMethod method) throws AuthenticationException {
+        Log_OC.d(TAG, "enter BearerScheme.authenticate(Credentials, HttpMethod)");
+
+        if (method == null) {
+            throw new IllegalArgumentException("Method may not be null");
+        }
+        BearerCredentials bearer = null;
+        try {
+            bearer = (BearerCredentials) credentials;
+        } catch (ClassCastException e) {
+            throw new InvalidCredentialsException(
+                    "Credentials cannot be used for bearer authentication: " 
+                    + credentials.getClass().getName());
+        }
+        return BearerAuthScheme.authenticate(
+            bearer, 
+            method.getParams().getCredentialCharset());
+    }
+    
+    /**
+     * @deprecated Use {@link #authenticate(BearerCredentials, String)}
+     * 
+     * Returns a bearer Authorization header value for the given 
+     * {@link BearerCredentials}.
+     * 
+     * @param   credentials     The credentials to encode.
+     * 
+     * @return                  A bearer authorization string
+     */
+    public static String authenticate(BearerCredentials credentials) {
+        return authenticate(credentials, "ISO-8859-1");
+    }
+
+    /**
+     * Returns a bearer Authorization header value for the given 
+     * {@link BearerCredentials} and charset.
+     * 
+     * @param   credentials         The credentials to encode.
+     * @param   charset             The charset to use for encoding the credentials
+     * 
+     * @return                      A bearer authorization string
+     * 
+     * @since 3.0
+     */
+    public static String authenticate(BearerCredentials credentials, String charset) {
+        Log_OC.d(TAG, "enter BearerAuthScheme.authenticate(BearerCredentials, String)");
+
+        if (credentials == null) {
+            throw new IllegalArgumentException("Credentials may not be null"); 
+        }
+        if (charset == null || charset.length() == 0) {
+            throw new IllegalArgumentException("charset may not be null or empty");
+        }
+        StringBuffer buffer = new StringBuffer();
+        buffer.append(credentials.getAccessToken());
+        
+        //return "Bearer " + EncodingUtil.getAsciiString(EncodingUtil.getBytes(buffer.toString(), charset));
+        return "Bearer " + buffer.toString();
+    }
+
+    /**
+     * Returns a String identifying the authentication challenge.  This is
+     * used, in combination with the host and port to determine if
+     * authorization has already been attempted or not.  Schemes which
+     * require multiple requests to complete the authentication should
+     * return a different value for each stage in the request.
+     * 
+     * Additionally, the ID should take into account any changes to the
+     * authentication challenge and return a different value when appropriate.
+     * For example when the realm changes in basic authentication it should be
+     * considered a different authentication attempt and a different value should
+     * be returned.
+     * 
+     * This method simply returns the realm for the challenge.
+     * 
+     * @return String       a String identifying the authentication challenge.
+     * 
+     * @deprecated no longer used
+     */
+    @Override
+    public String getID() {
+        return getRealm();
+    }
+
+    /**
+     * Returns authentication parameter with the given name, if available.
+     * 
+     * @param   name    The name of the parameter to be returned
+     * 
+     * @return          The parameter with the given name
+     */
+    @Override
+    public String getParameter(String name) {
+        if (name == null) {
+            throw new IllegalArgumentException("Parameter name may not be null"); 
+        }
+        if (mParams == null) {
+            return null;
+        }
+        return (String) mParams.get(name.toLowerCase());
+    }
+
+    /**
+     * Returns authentication realm. The realm may not be null.
+     * 
+     * @return  The authentication realm
+     */
+    @Override
+    public String getRealm() {
+        return getParameter("realm");
+    }
+    
+}
diff --git a/src/com/owncloud/android/network/BearerCredentials.java b/src/com/owncloud/android/network/BearerCredentials.java
new file mode 100644 (file)
index 0000000..50799b0
--- /dev/null
@@ -0,0 +1,97 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2012  ownCloud Inc.
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License version 2,
+ *   as published by the Free Software Foundation.
+ *
+ *   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 com.owncloud.android.network;
+
+import org.apache.commons.httpclient.Credentials;
+import org.apache.commons.httpclient.util.LangUtils;
+
+/**
+ * Bearer token {@link Credentials}
+ *
+ * @author David A. Velasco
+ */
+public class BearerCredentials implements Credentials {
+
+    
+    private String mAccessToken;
+    
+    
+    /**
+     * The constructor with the bearer token
+     *
+     * @param token     The bearer token
+     */
+    public BearerCredentials(String token) {
+        /*if (token == null) {
+            throw new IllegalArgumentException("Bearer token may not be null");            
+        }*/
+        mAccessToken = (token == null) ? "" : token;
+    }
+
+
+    /**
+     * Returns the access token
+     *
+     * @return      The access token
+     */
+    public String getAccessToken() {
+        return mAccessToken;
+    }
+
+
+    /**
+     * Get this object string.
+     *
+     * @return  The access token
+     */
+    public String toString() {
+        return mAccessToken;
+    }
+
+    /**
+     * Does a hash of the access token.
+     *
+     * @return The hash code of the access token
+     */
+    public int hashCode() {
+        int hash = LangUtils.HASH_SEED;
+        hash = LangUtils.hashCode(hash, mAccessToken);
+        return hash;
+    }
+
+    /**
+     * These credentials are assumed equal if accessToken is the same.
+     *
+     * @param   o   The other object to compare with.
+     *
+     * @return      'True' if the object is equivalent.
+     */
+    public boolean equals(Object o) {
+        if (o == null) return false;
+        if (this == o) return true;
+        if (this.getClass().equals(o.getClass())) {
+            BearerCredentials that = (BearerCredentials) o;
+            if (LangUtils.equals(mAccessToken, that.mAccessToken)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+}
+
index 02ff3f0..5d852d8 100644 (file)
@@ -37,19 +37,24 @@ import org.apache.http.conn.ssl.BrowserCompatHostnameVerifier;
 import org.apache.http.conn.ssl.X509HostnameVerifier;
 
 import com.owncloud.android.AccountUtils;
+import com.owncloud.android.authentication.AccountAuthenticator;
 import com.owncloud.android.Log_OC;
 
 import eu.alefzero.webdav.WebdavClient;
 
 import android.accounts.Account;
 import android.accounts.AccountManager;
+import android.accounts.AccountManagerFuture;
+import android.accounts.AuthenticatorException;
+import android.accounts.OperationCanceledException;
+import android.app.Activity;
 import android.content.Context;
 import android.net.Uri;
-import android.util.Log;
+import android.os.Bundle;
 
 public class OwnCloudClientUtils {
     
-    final private static String TAG = "OwnCloudClientFactory";
+    final private static String TAG = OwnCloudClientUtils.class.getSimpleName();
     
     /** Default timeout for waiting data from the server */
     public static final int DEFAULT_DATA_TIMEOUT = 60000;
@@ -70,46 +75,61 @@ public class OwnCloudClientUtils {
     /**
      * Creates a WebdavClient setup for an ownCloud account
      * 
-     * @param account   The ownCloud account
-     * @param context   The application context
-     * @return          A WebdavClient object ready to be used
+     * Do not call this method from the main thread.
+     * 
+     * @param account                       The ownCloud account
+     * @param appContext                    Android application context
+     * @return                              A WebdavClient object ready to be used
+     * @throws AuthenticatorException       If the authenticator failed to get the authorization token for the account.
+     * @throws OperationCanceledException   If the authenticator operation was cancelled while getting the authorization token for the account. 
+     * @throws IOException                  If there was some I/O error while getting the authorization token for the account.
      */
-    public static WebdavClient createOwnCloudClient (Account account, Context context) {
-        Log_OC.d(TAG, "Creating WebdavClient associated to " + account.name);
+    public static WebdavClient createOwnCloudClient (Account account, Context appContext) throws OperationCanceledException, AuthenticatorException, IOException {
+        //Log_OC.d(TAG, "Creating WebdavClient associated to " + account.name);
        
-        Uri uri = Uri.parse(AccountUtils.constructFullURLForAccount(context, account));
-        WebdavClient client = createOwnCloudClient(uri, context);
+        Uri uri = Uri.parse(AccountUtils.constructFullURLForAccount(appContext, account));
+        WebdavClient client = createOwnCloudClient(uri, appContext);
+        AccountManager am = AccountManager.get(appContext);
+        if (am.getUserData(account, AccountAuthenticator.KEY_SUPPORTS_OAUTH2) != null) {    // TODO avoid a call to getUserData here
+            String accessToken = am.blockingGetAuthToken(account, AccountAuthenticator.AUTH_TOKEN_TYPE_ACCESS_TOKEN, false);
+            client.setBearerCredentials(accessToken);   // TODO not assume that the access token is a bearer token
         
-        String username = account.name.substring(0, account.name.lastIndexOf('@'));
-        String password = AccountManager.get(context).getPassword(account);
-        //String password = am.blockingGetAuthToken(mAccount, AccountAuthenticator.AUTH_TOKEN_TYPE, true);
-        
-        client.setCredentials(username, password);
+        } else {
+            String username = account.name.substring(0, account.name.lastIndexOf('@'));
+            //String password = am.getPassword(account);
+            String password = am.blockingGetAuthToken(account, AccountAuthenticator.AUTH_TOKEN_TYPE_PASSWORD, false);
+            client.setBasicCredentials(username, password);
+        }
         
         return client;
     }
     
     
-    /**
-     * Creates a WebdavClient to try a new account before saving it
-     * 
-     * @param uri       URL to the ownCloud server
-     * @param username  User name
-     * @param password  User password
-     * @param context   Android context where the WebdavClient is being created.
-     * @return          A WebdavClient object ready to be used
-     */
-    public static WebdavClient createOwnCloudClient(Uri uri, String username, String password, Context context) {
-        Log_OC.d(TAG, "Creating WebdavClient for " + username + "@" + uri);
-        
-        WebdavClient client = createOwnCloudClient(uri, context);
-        
-        client.setCredentials(username, password);
+    public static WebdavClient createOwnCloudClient (Account account, Context appContext, Activity currentActivity) throws OperationCanceledException, AuthenticatorException, IOException {
+        Uri uri = Uri.parse(AccountUtils.constructFullURLForAccount(appContext, account));
+        WebdavClient client = createOwnCloudClient(uri, appContext);
+        AccountManager am = AccountManager.get(appContext);
+        if (am.getUserData(account, AccountAuthenticator.KEY_SUPPORTS_OAUTH2) != null) {    // TODO avoid a call to getUserData here
+            AccountManagerFuture<Bundle> future =  am.getAuthToken(account, AccountAuthenticator.AUTH_TOKEN_TYPE_ACCESS_TOKEN, null, currentActivity, null, null);
+            Bundle result = future.getResult();
+            String accessToken = result.getString(AccountManager.KEY_AUTHTOKEN);
+            //String accessToken = am.blockingGetAuthToken(account, AccountAuthenticator.AUTH_TOKEN_TYPE_ACCESS_TOKEN, false);
+            if (accessToken == null) throw new AuthenticatorException("WTF!");
+            client.setBearerCredentials(accessToken);   // TODO not assume that the access token is a bearer token
+            
+        } else {
+            String username = account.name.substring(0, account.name.lastIndexOf('@'));
+            //String password = am.getPassword(account);
+            //String password = am.blockingGetAuthToken(account, AccountAuthenticator.AUTH_TOKEN_TYPE_PASSWORD, false);
+            AccountManagerFuture<Bundle> future =  am.getAuthToken(account, AccountAuthenticator.AUTH_TOKEN_TYPE_PASSWORD, null, currentActivity, null, null);
+            Bundle result = future.getResult();
+            String password = result.getString(AccountManager.KEY_AUTHTOKEN);
+            client.setBasicCredentials(username, password);
+        }
         
         return client;
     }
     
-    
     /**
      * Creates a WebdavClient to access a URL and sets the desired parameters for ownCloud client connections.
      * 
@@ -118,7 +138,7 @@ public class OwnCloudClientUtils {
      * @return          A WebdavClient object ready to be used
      */
     public static WebdavClient createOwnCloudClient(Uri uri, Context context) {
-        Log_OC.d(TAG, "Creating WebdavClient for " + uri);
+        //Log_OC.d(TAG, "Creating WebdavClient for " + uri);
         
         //allowSelfsignedCertificates(true);
         try {
@@ -244,4 +264,5 @@ public class OwnCloudClientUtils {
         return mConnManager;
     }
 
+
 }
index b4f440f..697c154 100644 (file)
@@ -32,7 +32,6 @@ import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.network.ProgressiveDataTransferer;
 
 import android.accounts.Account;
-import android.util.Log;
 
 import eu.alefzero.webdav.ChunkFromFileChannelRequestEntity;
 import eu.alefzero.webdav.WebdavClient;
diff --git a/src/com/owncloud/android/operations/ConnectionCheckOperation.java b/src/com/owncloud/android/operations/ConnectionCheckOperation.java
deleted file mode 100644 (file)
index 34b64f8..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2013 ownCloud Inc.
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License version 2,
- *   as published by the Free Software Foundation.
- *
- *   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 com.owncloud.android.operations;
-
-import org.apache.commons.httpclient.HttpStatus;
-import org.apache.commons.httpclient.methods.GetMethod;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import com.owncloud.android.AccountUtils;
-import com.owncloud.android.Log_OC;
-import com.owncloud.android.utils.OwnCloudVersion;
-
-import eu.alefzero.webdav.WebdavClient;
-import android.content.Context;
-import android.net.ConnectivityManager;
-import android.net.Uri;
-import android.util.Log;
-
-public class ConnectionCheckOperation extends RemoteOperation {
-    
-    /** Maximum time to wait for a response from the server when the connection is being tested, in MILLISECONDs.  */
-    public static final int TRY_CONNECTION_TIMEOUT = 5000;
-    
-    private static final String TAG = ConnectionCheckOperation.class.getSimpleName();
-    
-    private String mUrl;
-    private RemoteOperationResult mLatestResult;
-    private Context mContext;
-    private OwnCloudVersion mOCVersion;
-
-    public ConnectionCheckOperation(String url, Context context) {
-        mUrl = url;
-        mContext = context;
-        mOCVersion = null;
-    }
-    
-    public OwnCloudVersion getDiscoveredVersion() {
-        return mOCVersion;
-    }
-
-    private boolean tryConnection(WebdavClient wc, String urlSt) {
-        boolean retval = false;
-        GetMethod get = null;
-        try {
-            get = new GetMethod(urlSt);
-            int status = wc.executeMethod(get, TRY_CONNECTION_TIMEOUT, TRY_CONNECTION_TIMEOUT);
-            String response = get.getResponseBodyAsString();
-            if (status == HttpStatus.SC_OK) {
-                JSONObject json = new JSONObject(response);
-                if (!json.getBoolean("installed")) {
-                    mLatestResult = new RemoteOperationResult(RemoteOperationResult.ResultCode.INSTANCE_NOT_CONFIGURED);
-                } else {
-                    mOCVersion = new OwnCloudVersion(json.getString("version"));
-                    if (!mOCVersion.isVersionValid()) {
-                        mLatestResult = new RemoteOperationResult(RemoteOperationResult.ResultCode.BAD_OC_VERSION);
-                        
-                    } else {
-                        mLatestResult = new RemoteOperationResult(urlSt.startsWith("https://") ? 
-                                                                    RemoteOperationResult.ResultCode.OK_SSL : 
-                                                                    RemoteOperationResult.ResultCode.OK_NO_SSL
-                            );
-
-                        retval = true;
-                    }
-                }
-                
-            } else {
-                mLatestResult = new RemoteOperationResult(false, status);
-            }
-
-        } catch (JSONException e) {
-            mLatestResult = new RemoteOperationResult(RemoteOperationResult.ResultCode.INSTANCE_NOT_CONFIGURED);
-            
-        } catch (Exception e) {
-            mLatestResult = new RemoteOperationResult(e);
-            
-        } finally {
-            if (get != null)
-                get.releaseConnection();
-        }
-        
-        if (mLatestResult.isSuccess()) {
-            Log_OC.i(TAG, "Connection check at " + urlSt + ": " + mLatestResult.getLogMessage());
-            
-        } else if (mLatestResult.getException() != null) {
-            Log_OC.e(TAG, "Connection check at " + urlSt + ": " + mLatestResult.getLogMessage(), mLatestResult.getException());
-            
-        } else {
-            Log_OC.e(TAG, "Connection check at " + urlSt + ": " + mLatestResult.getLogMessage());
-        }
-
-        return retval;
-    }
-
-    private boolean isOnline() {
-        ConnectivityManager cm = (ConnectivityManager) mContext
-                .getSystemService(Context.CONNECTIVITY_SERVICE);
-        return cm != null && cm.getActiveNetworkInfo() != null
-                && cm.getActiveNetworkInfo().isConnectedOrConnecting();
-    }
-
-       @Override
-       protected RemoteOperationResult run(WebdavClient client) {
-        if (!isOnline()) {
-               return new RemoteOperationResult(RemoteOperationResult.ResultCode.NO_NETWORK_CONNECTION);
-        }
-        if (mUrl.startsWith("http://") || mUrl.startsWith("https://")) {
-            tryConnection(client, mUrl + AccountUtils.STATUS_PATH);
-            
-        } else {
-            client.setBaseUri(Uri.parse("https://" + mUrl + AccountUtils.STATUS_PATH));
-            boolean httpsSuccess = tryConnection(client, "https://" + mUrl + AccountUtils.STATUS_PATH); 
-            if (!httpsSuccess && !mLatestResult.isSslRecoverableException()) {
-                Log_OC.d(TAG, "establishing secure connection failed, trying non secure connection");
-                client.setBaseUri(Uri.parse("http://" + mUrl + AccountUtils.STATUS_PATH));
-                tryConnection(client, "http://" + mUrl + AccountUtils.STATUS_PATH);
-            }
-        }
-        return mLatestResult;
-       }
-       
-}
diff --git a/src/com/owncloud/android/operations/CreateFolderOperation.java b/src/com/owncloud/android/operations/CreateFolderOperation.java
new file mode 100644 (file)
index 0000000..5965db3
--- /dev/null
@@ -0,0 +1,94 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2012 ownCloud Inc.
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License version 2,
+ *   as published by the Free Software Foundation.
+ *
+ *   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 com.owncloud.android.operations;
+
+import org.apache.jackrabbit.webdav.client.methods.MkColMethod;
+
+import com.owncloud.android.Log_OC;
+import com.owncloud.android.datamodel.DataStorageManager;
+import com.owncloud.android.datamodel.OCFile;
+
+import eu.alefzero.webdav.WebdavClient;
+import eu.alefzero.webdav.WebdavUtils;
+
+/**
+ * Remote operation performing the creation of a new folder in the ownCloud server.
+ * 
+ * @author David A. Velasco 
+ */
+public class CreateFolderOperation extends RemoteOperation {
+    
+    private static final String TAG = CreateFolderOperation.class.getSimpleName();
+
+    private static final int READ_TIMEOUT = 10000;
+    private static final int CONNECTION_TIMEOUT = 5000;
+    
+    protected String mRemotePath;
+    protected long mParentDirId;
+    protected DataStorageManager mStorageManager;
+    
+    /**
+     * Constructor
+     * 
+     * @param remoetPath            Full path to the new directory to create in the remote server.
+     * @param parentDirId           Local database id for the parent folder.
+     * @param storageManager        Reference to the local database corresponding to the account where the file is contained. 
+     */
+    public CreateFolderOperation(String remotePath, long parentDirId, DataStorageManager storageManager) {
+        mRemotePath = remotePath;
+        mParentDirId = parentDirId;
+        mStorageManager = storageManager;
+    }
+    
+    
+    /**
+     * Performs the remove operation
+     * 
+     * @param   client      Client object to communicate with the remote ownCloud server.
+     */
+    @Override
+    protected RemoteOperationResult run(WebdavClient client) {
+        RemoteOperationResult result = null;
+        MkColMethod mkcol = null;
+        try {
+            mkcol = new MkColMethod(client.getBaseUri() + WebdavUtils.encodePath(mRemotePath));
+            int status =  client.executeMethod(mkcol, READ_TIMEOUT, CONNECTION_TIMEOUT);
+            if (mkcol.succeeded()) {
+                // Save new directory in local database
+                OCFile newDir = new OCFile(mRemotePath);
+                newDir.setMimetype("DIR");
+                newDir.setParentId(mParentDirId);
+                mStorageManager.saveFile(newDir);
+            }
+
+            result = new RemoteOperationResult(mkcol.succeeded(), status);
+            Log_OC.d(TAG, "Create directory " + mRemotePath + ": " + result.getLogMessage());
+            client.exhaustResponse(mkcol.getResponseBodyAsStream());
+                
+        } catch (Exception e) {
+            result = new RemoteOperationResult(e);
+            Log_OC.e(TAG, "Create directory " + mRemotePath + ": " + result.getLogMessage(), e);
+            
+        } finally {
+            if (mkcol != null)
+                mkcol.releaseConnection();
+        }
+        return result;
+    }
+    
+}
index cb4355f..5745b97 100644 (file)
@@ -42,7 +42,6 @@ import eu.alefzero.webdav.OnDatatransferProgressListener;
 import eu.alefzero.webdav.WebdavClient;
 import eu.alefzero.webdav.WebdavUtils;
 import android.accounts.Account;
-import android.util.Log;
 import android.webkit.MimeTypeMap;
 
 /**
diff --git a/src/com/owncloud/android/operations/ExistenceCheckOperation.java b/src/com/owncloud/android/operations/ExistenceCheckOperation.java
new file mode 100644 (file)
index 0000000..1093986
--- /dev/null
@@ -0,0 +1,94 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2012 ownCloud Inc.
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License version 2,
+ *   as published by the Free Software Foundation.
+ *
+ *   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 com.owncloud.android.operations;
+
+import org.apache.commons.httpclient.HttpStatus;
+import org.apache.commons.httpclient.methods.HeadMethod;
+
+import com.owncloud.android.Log_OC;
+
+import eu.alefzero.webdav.WebdavClient;
+import android.content.Context;
+import android.net.ConnectivityManager;
+
+/**
+ * Operation to check the existence or absence of a path in a remote server.
+ * 
+ * @author David A. Velasco
+ */
+public class ExistenceCheckOperation extends RemoteOperation {
+    
+    /** Maximum time to wait for a response from the server in MILLISECONDs.  */
+    public static final int TIMEOUT = 10000;
+    
+    private static final String TAG = ExistenceCheckOperation.class.getSimpleName();
+    
+    private String mPath;
+    private Context mContext;
+    private boolean mSuccessIfAbsent;
+
+    
+    /**
+     * Full constructor. Success of the operation will depend upon the value of successIfAbsent.
+     * 
+     * @param path              Path to append to the URL owned by the client instance.
+     * @param context           Android application context.
+     * @param successIfAbsent   When 'true', the operation finishes in success if the path does NOT exist in the remote server (HTTP 404).
+     */
+    public ExistenceCheckOperation(String path, Context context, boolean successIfAbsent) {
+        mPath = (path != null) ? path : "";
+        mContext = context;
+        mSuccessIfAbsent = successIfAbsent;
+    }
+    
+
+       @Override
+       protected RemoteOperationResult run(WebdavClient client) {
+        if (!isOnline()) {
+            return new RemoteOperationResult(RemoteOperationResult.ResultCode.NO_NETWORK_CONNECTION);
+        }
+        RemoteOperationResult result = null;
+        HeadMethod head = null;
+        try {
+            head = new HeadMethod(client.getBaseUri() + mPath);
+            int status = client.executeMethod(head, TIMEOUT, TIMEOUT);
+            client.exhaustResponse(head.getResponseBodyAsStream());
+            boolean success = (status == HttpStatus.SC_OK && !mSuccessIfAbsent) || (status == HttpStatus.SC_NOT_FOUND && mSuccessIfAbsent);
+            result = new RemoteOperationResult(success, status);
+            Log_OC.d(TAG, "Existence check for " + client.getBaseUri() + mPath + " targeting for " + (mSuccessIfAbsent ? " absence " : " existence ") + "finished with HTTP status " + status + (!success?"(FAIL)":""));
+            
+        } catch (Exception e) {
+            result = new RemoteOperationResult(e);
+            Log_OC.e(TAG, "Existence check for " + client.getBaseUri() + mPath + " targeting for " + (mSuccessIfAbsent ? " absence " : " existence ") + ": " + result.getLogMessage(), result.getException());
+            
+        } finally {
+            if (head != null)
+                head.releaseConnection();
+        }
+        return result;
+       }
+
+    private boolean isOnline() {
+        ConnectivityManager cm = (ConnectivityManager) mContext
+                .getSystemService(Context.CONNECTIVITY_SERVICE);
+        return cm != null && cm.getActiveNetworkInfo() != null
+                && cm.getActiveNetworkInfo().isConnectedOrConnecting();
+    }
+
+
+}
diff --git a/src/com/owncloud/android/operations/OAuth2GetAccessToken.java b/src/com/owncloud/android/operations/OAuth2GetAccessToken.java
new file mode 100644 (file)
index 0000000..6d43caf
--- /dev/null
@@ -0,0 +1,174 @@
+package com.owncloud.android.operations;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.httpclient.methods.PostMethod;
+import org.apache.commons.httpclient.NameValuePair;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import com.owncloud.android.Log_OC;
+import com.owncloud.android.authentication.OAuth2Constants;
+import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
+
+import eu.alefzero.webdav.WebdavClient;
+
+public class OAuth2GetAccessToken extends RemoteOperation {
+    
+    private static final String TAG = OAuth2GetAccessToken.class.getSimpleName();
+    
+    private String mClientId;
+    private String mRedirectUri;
+    private String mGrantType;
+    
+    private String mOAuth2AuthorizationResponse;
+    private Map<String, String> mOAuth2ParsedAuthorizationResponse;
+    private Map<String, String> mResultTokenMap;
+
+    
+    public OAuth2GetAccessToken(String clientId, String redirectUri, String grantType, String oAuth2AuthorizationResponse) {
+        mClientId = clientId;
+        mRedirectUri = redirectUri;
+        mGrantType = grantType;
+        mOAuth2AuthorizationResponse = oAuth2AuthorizationResponse;
+        mOAuth2ParsedAuthorizationResponse = new HashMap<String, String>();
+        mResultTokenMap = null;
+    }
+    
+    
+    public Map<String, String> getOauth2AutorizationResponse() {
+        return mOAuth2ParsedAuthorizationResponse;
+    }
+
+    public Map<String, String> getResultTokenMap() {
+        return mResultTokenMap;
+    }
+    
+    @Override
+    protected RemoteOperationResult run(WebdavClient client) {
+        RemoteOperationResult result = null;
+        PostMethod postMethod = null;
+        
+        try {
+            parseAuthorizationResponse();
+            if (mOAuth2ParsedAuthorizationResponse.keySet().contains(OAuth2Constants.KEY_ERROR)) {
+                if (OAuth2Constants.VALUE_ERROR_ACCESS_DENIED.equals(mOAuth2ParsedAuthorizationResponse.get(OAuth2Constants.KEY_ERROR))) {
+                    result = new RemoteOperationResult(ResultCode.OAUTH2_ERROR_ACCESS_DENIED);
+                } else {
+                    result = new RemoteOperationResult(ResultCode.OAUTH2_ERROR);
+                }
+            }
+            
+            if (result == null) { 
+                NameValuePair[] nameValuePairs = new NameValuePair[4];
+                nameValuePairs[0] = new NameValuePair(OAuth2Constants.KEY_GRANT_TYPE, mGrantType);
+                nameValuePairs[1] = new NameValuePair(OAuth2Constants.KEY_CODE, mOAuth2ParsedAuthorizationResponse.get(OAuth2Constants.KEY_CODE));            
+                nameValuePairs[2] = new NameValuePair(OAuth2Constants.KEY_REDIRECT_URI, mRedirectUri);       
+                nameValuePairs[3] = new NameValuePair(OAuth2Constants.KEY_CLIENT_ID, mClientId);
+                //nameValuePairs[4] = new NameValuePair(OAuth2Constants.KEY_SCOPE, mOAuth2ParsedAuthorizationResponse.get(OAuth2Constants.KEY_SCOPE));         
+                
+                postMethod = new PostMethod(client.getBaseUri().toString());
+                postMethod.setRequestBody(nameValuePairs);
+                int status = client.executeMethod(postMethod);
+                
+                String response = postMethod.getResponseBodyAsString();
+                if (response != null && response.length() > 0) {
+                    JSONObject tokenJson = new JSONObject(response);
+                    parseAccessTokenResult(tokenJson);
+                    if (mResultTokenMap.get(OAuth2Constants.KEY_ERROR) != null || mResultTokenMap.get(OAuth2Constants.KEY_ACCESS_TOKEN) == null) {
+                        result = new RemoteOperationResult(ResultCode.OAUTH2_ERROR);
+                    
+                    } else {
+                        result = new RemoteOperationResult(true, status);
+                    }
+                    
+                } else {
+                    client.exhaustResponse(postMethod.getResponseBodyAsStream());
+                    result = new RemoteOperationResult(false, status);
+                }
+            }
+            
+        } catch (Exception e) {
+            result = new RemoteOperationResult(e);
+            
+        } finally {
+            if (postMethod != null)
+                postMethod.releaseConnection();    // let the connection available for other methods
+            
+            if (result.isSuccess()) {
+                Log_OC.i(TAG, "OAuth2 TOKEN REQUEST with auth code " + mOAuth2ParsedAuthorizationResponse.get("code") + " to " + client.getBaseUri() + ": " + result.getLogMessage());
+            
+            } else if (result.getException() != null) {
+                Log_OC.e(TAG, "OAuth2 TOKEN REQUEST with auth code " + mOAuth2ParsedAuthorizationResponse.get("code") + " to " + client.getBaseUri() + ": " + result.getLogMessage(), result.getException());
+                
+            } else if (result.getCode() == ResultCode.OAUTH2_ERROR) {
+                Log_OC.e(TAG, "OAuth2 TOKEN REQUEST with auth code " + mOAuth2ParsedAuthorizationResponse.get("code") + " to " + client.getBaseUri() + ": " + ((mResultTokenMap != null) ? mResultTokenMap.get(OAuth2Constants.KEY_ERROR) : "NULL"));
+                    
+            } else {
+                Log_OC.e(TAG, "OAuth2 TOKEN REQUEST with auth code " + mOAuth2ParsedAuthorizationResponse.get("code") + " to " + client.getBaseUri() + ": " + result.getLogMessage());
+            }
+        }
+        
+        return result;
+    }
+    
+    
+    private void parseAuthorizationResponse() {
+        String[] pairs = mOAuth2AuthorizationResponse.split("&");
+        int i = 0;
+        String key = "";
+        String value = "";
+        StringBuilder sb = new StringBuilder();
+        while (pairs.length > i) {
+            int j = 0;
+            String[] part = pairs[i].split("=");
+            while (part.length > j) {
+                String p = part[j];
+                if (j == 0) {
+                    key = p;
+                    sb.append(key + " = ");
+                } else if (j == 1) {
+                    value = p;
+                    mOAuth2ParsedAuthorizationResponse.put(key, value);
+                    sb.append(value + "\n");
+                }
+
+                Log_OC.v(TAG, "[" + i + "," + j + "] = " + p);
+                j++;
+            }
+            i++;
+        }
+    }
+
+
+    private void parseAccessTokenResult (JSONObject tokenJson) throws JSONException {
+        mResultTokenMap = new HashMap<String, String>();
+        
+        if (tokenJson.has(OAuth2Constants.KEY_ACCESS_TOKEN)) {
+            mResultTokenMap.put(OAuth2Constants.KEY_ACCESS_TOKEN, tokenJson.getString(OAuth2Constants.KEY_ACCESS_TOKEN));
+        }
+        if (tokenJson.has(OAuth2Constants.KEY_TOKEN_TYPE)) {
+            mResultTokenMap.put(OAuth2Constants.KEY_TOKEN_TYPE, tokenJson.getString(OAuth2Constants.KEY_TOKEN_TYPE));
+        }
+        if (tokenJson.has(OAuth2Constants.KEY_EXPIRES_IN)) {
+            mResultTokenMap.put(OAuth2Constants.KEY_EXPIRES_IN, tokenJson.getString(OAuth2Constants.KEY_EXPIRES_IN));
+        }
+        if (tokenJson.has(OAuth2Constants.KEY_REFRESH_TOKEN)) {
+            mResultTokenMap.put(OAuth2Constants.KEY_REFRESH_TOKEN, tokenJson.getString(OAuth2Constants.KEY_REFRESH_TOKEN));
+        }
+        if (tokenJson.has(OAuth2Constants.KEY_SCOPE)) {
+            mResultTokenMap.put(OAuth2Constants.KEY_SCOPE, tokenJson.getString(OAuth2Constants.KEY_SCOPE));
+        }
+        if (tokenJson.has(OAuth2Constants.KEY_ERROR)) {
+            mResultTokenMap.put(OAuth2Constants.KEY_ERROR, tokenJson.getString(OAuth2Constants.KEY_ERROR));
+        }
+        if (tokenJson.has(OAuth2Constants.KEY_ERROR_DESCRIPTION)) {
+            mResultTokenMap.put(OAuth2Constants.KEY_ERROR_DESCRIPTION, tokenJson.getString(OAuth2Constants.KEY_ERROR_DESCRIPTION));
+        }
+        if (tokenJson.has(OAuth2Constants.KEY_ERROR_URI)) {
+            mResultTokenMap.put(OAuth2Constants.KEY_ERROR_URI, tokenJson.getString(OAuth2Constants.KEY_ERROR_URI));
+        }
+    }
+
+}
diff --git a/src/com/owncloud/android/operations/OwnCloudServerCheckOperation.java b/src/com/owncloud/android/operations/OwnCloudServerCheckOperation.java
new file mode 100644 (file)
index 0000000..1afcf6e
--- /dev/null
@@ -0,0 +1,137 @@
+/* ownCloud Android client application
+ *   Copyright (C) 2012-2013 ownCloud Inc.
+ *
+ *   This program is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License version 2,
+ *   as published by the Free Software Foundation.
+ *
+ *   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 com.owncloud.android.operations;
+
+import org.apache.commons.httpclient.HttpStatus;
+import org.apache.commons.httpclient.methods.GetMethod;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import com.owncloud.android.AccountUtils;
+import com.owncloud.android.Log_OC;
+import com.owncloud.android.utils.OwnCloudVersion;
+
+import eu.alefzero.webdav.WebdavClient;
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.Uri;
+
+public class OwnCloudServerCheckOperation extends RemoteOperation {
+    
+    /** Maximum time to wait for a response from the server when the connection is being tested, in MILLISECONDs.  */
+    public static final int TRY_CONNECTION_TIMEOUT = 5000;
+    
+    private static final String TAG = OwnCloudServerCheckOperation.class.getSimpleName();
+    
+    private String mUrl;
+    private RemoteOperationResult mLatestResult;
+    private Context mContext;
+    private OwnCloudVersion mOCVersion;
+
+    public OwnCloudServerCheckOperation(String url, Context context) {
+        mUrl = url;
+        mContext = context;
+        mOCVersion = null;
+    }
+    
+    public OwnCloudVersion getDiscoveredVersion() {
+        return mOCVersion;
+    }
+
+    private boolean tryConnection(WebdavClient wc, String urlSt) {
+        boolean retval = false;
+        GetMethod get = null;
+        try {
+            get = new GetMethod(urlSt);
+            int status = wc.executeMethod(get, TRY_CONNECTION_TIMEOUT, TRY_CONNECTION_TIMEOUT);
+            String response = get.getResponseBodyAsString();
+            if (status == HttpStatus.SC_OK) {
+                JSONObject json = new JSONObject(response);
+                if (!json.getBoolean("installed")) {
+                    mLatestResult = new RemoteOperationResult(RemoteOperationResult.ResultCode.INSTANCE_NOT_CONFIGURED);
+                } else {
+                    mOCVersion = new OwnCloudVersion(json.getString("version"));
+                    if (!mOCVersion.isVersionValid()) {
+                        mLatestResult = new RemoteOperationResult(RemoteOperationResult.ResultCode.BAD_OC_VERSION);
+                        
+                    } else {
+                        mLatestResult = new RemoteOperationResult(urlSt.startsWith("https://") ? 
+                                                                    RemoteOperationResult.ResultCode.OK_SSL : 
+                                                                    RemoteOperationResult.ResultCode.OK_NO_SSL
+                            );
+
+                        retval = true;
+                    }
+                }
+                
+            } else {
+                mLatestResult = new RemoteOperationResult(false, status);
+            }
+
+        } catch (JSONException e) {
+            mLatestResult = new RemoteOperationResult(RemoteOperationResult.ResultCode.INSTANCE_NOT_CONFIGURED);
+            
+        } catch (Exception e) {
+            mLatestResult = new RemoteOperationResult(e);
+            
+        } finally {
+            if (get != null)
+                get.releaseConnection();
+        }
+        
+        if (mLatestResult.isSuccess()) {
+            Log_OC.i(TAG, "Connection check at " + urlSt + ": " + mLatestResult.getLogMessage());
+            
+        } else if (mLatestResult.getException() != null) {
+            Log_OC.e(TAG, "Connection check at " + urlSt + ": " + mLatestResult.getLogMessage(), mLatestResult.getException());
+            
+        } else {
+            Log_OC.e(TAG, "Connection check at " + urlSt + ": " + mLatestResult.getLogMessage());
+        }
+
+        return retval;
+    }
+
+    private boolean isOnline() {
+        ConnectivityManager cm = (ConnectivityManager) mContext
+                .getSystemService(Context.CONNECTIVITY_SERVICE);
+        return cm != null && cm.getActiveNetworkInfo() != null
+                && cm.getActiveNetworkInfo().isConnectedOrConnecting();
+    }
+
+       @Override
+       protected RemoteOperationResult run(WebdavClient client) {
+        if (!isOnline()) {
+               return new RemoteOperationResult(RemoteOperationResult.ResultCode.NO_NETWORK_CONNECTION);
+        }
+        if (mUrl.startsWith("http://") || mUrl.startsWith("https://")) {
+            tryConnection(client, mUrl + AccountUtils.STATUS_PATH);
+            
+        } else {
+            client.setBaseUri(Uri.parse("https://" + mUrl + AccountUtils.STATUS_PATH));
+            boolean httpsSuccess = tryConnection(client, "https://" + mUrl + AccountUtils.STATUS_PATH); 
+            if (!httpsSuccess && !mLatestResult.isSslRecoverableException()) {
+                Log_OC.d(TAG, "establishing secure connection failed, trying non secure connection");
+                client.setBaseUri(Uri.parse("http://" + mUrl + AccountUtils.STATUS_PATH));
+                tryConnection(client, "http://" + mUrl + AccountUtils.STATUS_PATH);
+            }
+        }
+        return mLatestResult;
+       }
+       
+}
index 6d99044..711a72b 100644 (file)
  */
 package com.owncloud.android.operations;
 
+import java.io.IOException;
+
+import org.apache.commons.httpclient.Credentials;
+
+import com.owncloud.android.Log_OC;
+import com.owncloud.android.authentication.AccountAuthenticator;
+import com.owncloud.android.network.BearerCredentials;
+import com.owncloud.android.network.OwnCloudClientUtils;
+import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.accounts.AccountsException;
+import android.app.Activity;
+import android.content.Context;
 import android.os.Handler;
 
 import eu.alefzero.webdav.WebdavClient;
@@ -29,7 +44,15 @@ import eu.alefzero.webdav.WebdavClient;
  */
 public abstract class RemoteOperation implements Runnable {
        
-       /** Object to interact with the ownCloud server */
+    private static final String TAG = RemoteOperation.class.getSimpleName();
+
+    /** ownCloud account in the remote ownCloud server to operate */
+    private Account mAccount = null;
+    
+    /** Android Application context */
+    private Context mContext = null;
+    
+       /** Object to interact with the remote server */
        private WebdavClient mClient = null;
        
        /** Callback object to notify about the execution of the remote operation */
@@ -38,16 +61,49 @@ public abstract class RemoteOperation implements Runnable {
        /** Handler to the thread where mListener methods will be called */
        private Handler mListenerHandler = null;
 
+       /** Activity */
+    private Activity mCallerActivity;
+
        
        /**
         *  Abstract method to implement the operation in derived classes.
         */
        protected abstract RemoteOperationResult run(WebdavClient client); 
        
+
+    /**
+     * Synchronously executes the remote operation on the received ownCloud account.
+     * 
+     * Do not call this method from the main thread.
+     * 
+     * This method should be used whenever an ownCloud account is available, instead of {@link #execute(WebdavClient)}. 
+     * 
+     * @param account   ownCloud account in remote ownCloud server to reach during the execution of the operation.
+     * @param context   Android context for the component calling the method.
+     * @return          Result of the operation.
+     */
+    public final RemoteOperationResult execute(Account account, Context context) {
+        if (account == null)
+            throw new IllegalArgumentException("Trying to execute a remote operation with a NULL Account");
+        if (context == null)
+            throw new IllegalArgumentException("Trying to execute a remote operation with a NULL Context");
+        mAccount = account;
+        mContext = context.getApplicationContext();
+        try {
+            mClient = OwnCloudClientUtils.createOwnCloudClient(mAccount, mContext);
+        } catch (Exception e) {
+            Log_OC.e(TAG, "Error while trying to access to " + mAccount.name, e);
+            return new RemoteOperationResult(e);
+        }
+        return run(mClient);
+    }
+    
        
        /**
         * Synchronously executes the remote operation
         * 
+     * Do not call this method from the main thread.
+     * 
         * @param client        Client object to reach an ownCloud server during the execution of the operation.
         * @return                      Result of the operation.
         */
@@ -59,6 +115,43 @@ public abstract class RemoteOperation implements Runnable {
        }
 
        
+    /**
+     * Asynchronously executes the remote operation
+     * 
+     * This method should be used whenever an ownCloud account is available, instead of {@link #execute(WebdavClient)}. 
+     * 
+     * @param account           ownCloud account in remote ownCloud server to reach during the execution of the operation.
+     * @param context           Android context for the component calling the method.
+     * @param listener          Listener to be notified about the execution of the operation.
+     * @param listenerHandler   Handler associated to the thread where the methods of the listener objects must be called.
+     * @return                  Thread were the remote operation is executed.
+     */
+    public final Thread execute(Account account, Context context, OnRemoteOperationListener listener, Handler listenerHandler, Activity callerActivity) {
+        if (account == null)
+            throw new IllegalArgumentException("Trying to execute a remote operation with a NULL Account");
+        if (context == null)
+            throw new IllegalArgumentException("Trying to execute a remote operation with a NULL Context");
+        mAccount = account;
+        mContext = context.getApplicationContext();
+        mCallerActivity = callerActivity;
+        mClient = null;     // the client instance will be created from mAccount and mContext in the runnerThread to create below
+        
+        if (listener == null) {
+            throw new IllegalArgumentException("Trying to execute a remote operation asynchronously without a listener to notiy the result");
+        }
+        mListener = listener;
+        
+        if (listenerHandler == null) {
+            throw new IllegalArgumentException("Trying to execute a remote operation asynchronously without a handler to the listener's thread");
+        }
+        mListenerHandler = listenerHandler;
+        
+        Thread runnerThread = new Thread(this);
+        runnerThread.start();
+        return runnerThread;
+    }
+
+    
        /**
         * Asynchronously executes the remote operation
         * 
@@ -115,20 +208,74 @@ public abstract class RemoteOperation implements Runnable {
         * Asynchronous execution of the operation 
         * started by {@link RemoteOperation#execute(WebdavClient, OnRemoteOperationListener, Handler)}, 
         * and result posting.
+        * 
+        * TODO refactor && clean the code; now it's a mess
         */
     @Override
     public final void run() {
-       final RemoteOperationResult result = execute(mClient);
+        RemoteOperationResult result = null;
+        boolean repeat = false;
+        do {
+            try{
+                if (mClient == null) {
+                    if (mAccount != null && mContext != null) {
+                        if (mCallerActivity != null) {
+                            mClient = OwnCloudClientUtils.createOwnCloudClient(mAccount, mContext, mCallerActivity);
+                        } else {
+                            mClient = OwnCloudClientUtils.createOwnCloudClient(mAccount, mContext);
+                        }
+                    } else {
+                        throw new IllegalStateException("Trying to run a remote operation asynchronously with no client instance or account");
+                    }
+                }
+            
+            } catch (IOException e) {
+                Log_OC.e(TAG, "Error while trying to access to " + mAccount.name, new AccountsException("I/O exception while trying to authorize the account", e));
+                result = new RemoteOperationResult(e);
+            
+            } catch (AccountsException e) {
+                Log_OC.e(TAG, "Error while trying to access to " + mAccount.name, e);
+                result = new RemoteOperationResult(e);
+            }
        
+            if (result == null)
+                result = run(mClient);
+        
+            repeat = false;
+            if (mCallerActivity != null && mAccount != null && mContext != null && !result.isSuccess() && result.getCode() == ResultCode.UNAUTHORIZED) {
+                /// fail due to lack of authorization in an operation performed in foreground
+                AccountManager am = AccountManager.get(mContext);
+                Credentials cred = mClient.getCredentials();
+                if (cred instanceof BearerCredentials) {
+                    am.invalidateAuthToken(AccountAuthenticator.ACCOUNT_TYPE, ((BearerCredentials)cred).getAccessToken());
+                } else {
+                    am.clearPassword(mAccount);
+                }
+                mClient = null;
+                repeat = true;  // when repeated, the creation of a new OwnCloudClient after erasing the saved credentials will trigger the login activity
+                result = null;
+            }
+        } while (repeat);
+        
+        final RemoteOperationResult resultToSend = result;
         if (mListenerHandler != null && mListener != null) {
                mListenerHandler.post(new Runnable() {
                 @Override
                 public void run() {
-                    mListener.onRemoteOperationFinish(RemoteOperation.this, result);
+                    mListener.onRemoteOperationFinish(RemoteOperation.this, resultToSend);
                 }
             });
         }
     }
-       
-       
+
+
+    /**
+     * Returns the current client instance to access the remote server.
+     * 
+     * @return      Current client instance to access the remote server.
+     */
+    public final WebdavClient getClient() {
+        return mClient;
+    }
+
 }
index db1771b..16b4779 100644 (file)
@@ -32,8 +32,6 @@ import org.apache.commons.httpclient.HttpException;
 import org.apache.commons.httpclient.HttpStatus;
 import org.apache.jackrabbit.webdav.DavException;
 
-import android.util.Log;
-
 import com.owncloud.android.Log_OC;
 import com.owncloud.android.network.CertificateCombinedException;
 
@@ -49,10 +47,37 @@ public class RemoteOperationResult implements Serializable {
 
     /** Generated - should be refreshed every time the class changes!! */
     private static final long serialVersionUID = -7805531062432602444L;
+    
     private static final String TAG = "RemoteOperationResult";
-
-    public enum ResultCode {
-        OK, OK_SSL, OK_NO_SSL, UNHANDLED_HTTP_CODE, UNAUTHORIZED, FILE_NOT_FOUND, INSTANCE_NOT_CONFIGURED, UNKNOWN_ERROR, WRONG_CONNECTION, TIMEOUT, INCORRECT_ADDRESS, HOST_NOT_AVAILABLE, NO_NETWORK_CONNECTION, SSL_ERROR, SSL_RECOVERABLE_PEER_UNVERIFIED, BAD_OC_VERSION, CANCELLED, INVALID_LOCAL_FILE_NAME, INVALID_OVERWRITE, CONFLICT, SYNC_CONFLICT, LOCAL_STORAGE_FULL, LOCAL_STORAGE_NOT_MOVED, LOCAL_STORAGE_NOT_COPIED, QUOTA_EXCEEDED
+    
+    public enum ResultCode { 
+        OK,
+        OK_SSL,
+        OK_NO_SSL,
+        UNHANDLED_HTTP_CODE,
+        UNAUTHORIZED,        
+        FILE_NOT_FOUND, 
+        INSTANCE_NOT_CONFIGURED, 
+        UNKNOWN_ERROR, 
+        WRONG_CONNECTION,  
+        TIMEOUT, 
+        INCORRECT_ADDRESS, 
+        HOST_NOT_AVAILABLE, 
+        NO_NETWORK_CONNECTION, 
+        SSL_ERROR,
+        SSL_RECOVERABLE_PEER_UNVERIFIED,
+        BAD_OC_VERSION,
+        CANCELLED, 
+        INVALID_LOCAL_FILE_NAME, 
+        INVALID_OVERWRITE,
+        CONFLICT, 
+        OAUTH2_ERROR,
+        SYNC_CONFLICT,
+        LOCAL_STORAGE_FULL, 
+        LOCAL_STORAGE_NOT_MOVED, 
+        LOCAL_STORAGE_NOT_COPIED, 
+        OAUTH2_ERROR_ACCESS_DENIED,
+        QUOTA_EXCEEDED
     }
 
     private boolean mSuccess = false;
index dc69948..8348b72 100644 (file)
@@ -20,8 +20,6 @@ package com.owncloud.android.operations;
 import org.apache.commons.httpclient.HttpStatus;
 import org.apache.jackrabbit.webdav.client.methods.DeleteMethod;
 
-import android.util.Log;
-
 import com.owncloud.android.Log_OC;
 import com.owncloud.android.datamodel.DataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
index 7ea5cf9..1c636fb 100644 (file)
@@ -24,7 +24,6 @@ import org.apache.jackrabbit.webdav.client.methods.DavMethodBase;
 //import org.apache.jackrabbit.webdav.client.methods.MoveMethod;
 
 import android.accounts.Account;
-import android.util.Log;
 
 import com.owncloud.android.Log_OC;
 import com.owncloud.android.datamodel.DataStorageManager;
@@ -42,7 +41,7 @@ import eu.alefzero.webdav.WebdavUtils;
  */
 public class RenameFileOperation extends RemoteOperation {
     
-    private static final String TAG = RemoveFileOperation.class.getSimpleName();
+    private static final String TAG = RenameFileOperation.class.getSimpleName();
 
     private static final int RENAME_READ_TIMEOUT = 10000;
     private static final int RENAME_CONNECTION_TIMEOUT = 5000;
index 0709310..b0f2ce2 100644 (file)
@@ -25,7 +25,6 @@ import org.apache.jackrabbit.webdav.client.methods.PropFindMethod;
 import android.accounts.Account;
 import android.content.Context;
 import android.content.Intent;
-import android.util.Log;
 
 import com.owncloud.android.Log_OC;
 import com.owncloud.android.datamodel.DataStorageManager;
index 843da11..3c1a64f 100644 (file)
@@ -34,7 +34,6 @@ import org.apache.jackrabbit.webdav.client.methods.PropFindMethod;
 
 import android.accounts.Account;
 import android.content.Context;
-import android.util.Log;
 
 import com.owncloud.android.Log_OC;
 import com.owncloud.android.datamodel.DataStorageManager;
index f9e4acb..dad5717 100644 (file)
@@ -25,11 +25,10 @@ import org.json.JSONObject;
 import android.accounts.Account;
 import android.accounts.AccountManager;
 import android.content.Context;
-import android.util.Log;
 
 import com.owncloud.android.AccountUtils;
+import com.owncloud.android.authentication.AccountAuthenticator;
 import com.owncloud.android.Log_OC;
-import com.owncloud.android.authenticator.AccountAuthenticator;
 import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
 import com.owncloud.android.utils.OwnCloudVersion;
 
index f9e0a48..9b03243 100644 (file)
@@ -37,7 +37,6 @@ import android.database.sqlite.SQLiteOpenHelper;
 import android.database.sqlite.SQLiteQueryBuilder;
 import android.net.Uri;
 import android.text.TextUtils;
-import android.util.Log;
 
 /**
  * The ContentProvider for the ownCloud App.
index fafb0cb..469ee3b 100644 (file)
@@ -142,7 +142,7 @@ public abstract class AbstractOwnCloudSyncAdapter extends
         return null;\r
     }\r
 \r
-    protected void initClientForCurrentAccount() throws UnknownHostException {\r
+    protected void initClientForCurrentAccount() throws OperationCanceledException, AuthenticatorException, IOException {\r
         if (AccountUtils.constructFullURLForAccount(getContext(), account) == null) {\r
             throw new UnknownHostException();\r
         }\r
index 0687146..b82a400 100644 (file)
@@ -25,7 +25,7 @@ import org.apache.http.client.methods.HttpPut;
 import org.apache.http.entity.ByteArrayEntity;
 
 import com.owncloud.android.AccountUtils;
-import com.owncloud.android.authenticator.AccountAuthenticator;
+import com.owncloud.android.authentication.AccountAuthenticator;
 
 import android.accounts.Account;
 import android.accounts.AccountManager;
index b3a42ea..ec8750c 100644 (file)
@@ -19,7 +19,6 @@
 package com.owncloud.android.syncadapter;
 
 import java.io.IOException;
-import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -29,6 +28,7 @@ import org.apache.jackrabbit.webdav.DavException;
 
 import com.owncloud.android.Log_OC;
 import com.owncloud.android.R;
+import com.owncloud.android.authentication.AuthenticatorActivity;
 import com.owncloud.android.datamodel.DataStorageManager;
 import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
@@ -38,6 +38,7 @@ import com.owncloud.android.operations.UpdateOCVersionOperation;
 import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
 import com.owncloud.android.ui.activity.ErrorsWhileCopyingHandlerActivity;
 import android.accounts.Account;
+import android.accounts.AccountsException;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
@@ -47,13 +48,13 @@ import android.content.Context;
 import android.content.Intent;
 import android.content.SyncResult;
 import android.os.Bundle;
-import android.util.Log;
 
 /**
  * SyncAdapter implementation for syncing sample SyncAdapter contacts to the
  * platform ContactOperations provider.
  * 
  * @author Bartek Przybylski
+ * @author David A. Velasco
  */
 public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
 
@@ -103,8 +104,13 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
         this.setStorageManager(new FileDataStorageManager(account, getContentProvider()));
         try {
             this.initClientForCurrentAccount();
-        } catch (UnknownHostException e) {
-            /// the account is unknown for the Synchronization Manager. unreachable for this context; don't try this again
+        } catch (IOException e) {
+            /// the account is unknown for the Synchronization Manager, or unreachable for this context; don't try this again
+            mSyncResult.tooManyRetries = true;
+            notifyFailedSynchronization();
+            return;
+        } catch (AccountsException e) {
+            /// the account is unknown for the Synchronization Manager, or unreachable for this context; don't try this again
             mSyncResult.tooManyRetries = true;
             notifyFailedSynchronization();
             return;
@@ -147,7 +153,6 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
         }
         
     }
-
     
     /**
      * Called by system SyncManager when a synchronization is required to be cancelled.
@@ -173,7 +178,6 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
             mLastFailedResult = result; 
         }
     }
-
     
     
     /**
@@ -292,12 +296,28 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
     private void notifyFailedSynchronization() {
         Notification notification = new Notification(R.drawable.icon, getContext().getString(R.string.sync_fail_ticker), System.currentTimeMillis());
         notification.flags |= Notification.FLAG_AUTO_CANCEL;
-        // TODO put something smart in the contentIntent below
+        boolean needsToUpdateCredentials = (mLastFailedResult != null && mLastFailedResult.getCode() == ResultCode.UNAUTHORIZED);
+        // TODO put something smart in the contentIntent below for all the possible errors
         notification.contentIntent = PendingIntent.getActivity(getContext().getApplicationContext(), (int)System.currentTimeMillis(), new Intent(), 0);
-        notification.setLatestEventInfo(getContext().getApplicationContext(), 
-                                        getContext().getString(R.string.sync_fail_ticker), 
-                                        String.format(getContext().getString(R.string.sync_fail_content), getAccount().name), 
-                                        notification.contentIntent);
+        if (needsToUpdateCredentials) {
+            // let the user update credentials with one click
+            Intent updateAccountCredentials = new Intent(getContext(), AuthenticatorActivity.class);
+            updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, getAccount());
+            updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACTION, AuthenticatorActivity.ACTION_UPDATE_TOKEN);
+            updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+            updateAccountCredentials.addFlags(Intent.FLAG_FROM_BACKGROUND);
+            notification.contentIntent = PendingIntent.getActivity(getContext(), (int)System.currentTimeMillis(), updateAccountCredentials, PendingIntent.FLAG_ONE_SHOT);
+            notification.setLatestEventInfo(getContext().getApplicationContext(), 
+                    getContext().getString(R.string.sync_fail_ticker), 
+                    String.format(getContext().getString(R.string.sync_fail_content_unauthorized), getAccount().name), 
+                    notification.contentIntent);
+        } else {
+            notification.setLatestEventInfo(getContext().getApplicationContext(), 
+                                            getContext().getString(R.string.sync_fail_ticker), 
+                                            String.format(getContext().getString(R.string.sync_fail_content), getAccount().name), 
+                                            notification.contentIntent);
+        }
         ((NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE)).notify(R.string.sync_fail_ticker, notification);
     }
 
@@ -331,7 +351,6 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
             ((NotificationManager) getContext().getSystemService(Context.NOTIFICATION_SERVICE)).notify(R.string.sync_conflicts_in_favourites_ticker, notification);
         } 
     }
-
     
     /**
      * Notifies the user about local copies of files out of the ownCloud local directory that were 'forgotten' because 
index 7a1cac5..be369dc 100644 (file)
@@ -32,7 +32,6 @@ import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
 import android.os.Handler;
-import android.util.Log;
 import android.view.ContextMenu;
 import android.view.View;
 import android.view.ViewGroup;
@@ -49,8 +48,8 @@ import com.actionbarsherlock.view.Menu;
 import com.actionbarsherlock.view.MenuInflater;
 import com.actionbarsherlock.view.MenuItem;
 import com.owncloud.android.AccountUtils;
+import com.owncloud.android.authentication.AccountAuthenticator;
 import com.owncloud.android.Log_OC;
-import com.owncloud.android.authenticator.AccountAuthenticator;
 
 import com.owncloud.android.R;
 
@@ -95,10 +94,10 @@ public class AccountSelectActivity extends SherlockListActivity implements
                 /// the account set as default changed since this activity was created 
             
                 // trigger synchronization
-                ContentResolver.cancelSync(null, AccountAuthenticator.AUTH_TOKEN_TYPE);
+                ContentResolver.cancelSync(null, AccountAuthenticator.AUTHORITY);
                 Bundle bundle = new Bundle();
                 bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
-                ContentResolver.requestSync(AccountUtils.getCurrentOwnCloudAccount(this), AccountAuthenticator.AUTH_TOKEN_TYPE, bundle);
+                ContentResolver.requestSync(AccountUtils.getCurrentOwnCloudAccount(this), AccountAuthenticator.AUTHORITY, bundle);
                 
                 // restart the main activity
                 Intent i = new Intent(this, FileDisplayActivity.class);
@@ -136,7 +135,7 @@ public class AccountSelectActivity extends SherlockListActivity implements
             Intent intent = new Intent(
                     android.provider.Settings.ACTION_ADD_ACCOUNT);
             intent.putExtra("authorities",
-                    new String[] { AccountAuthenticator.AUTH_TOKEN_TYPE });
+                    new String[] { AccountAuthenticator.AUTHORITY });
             startActivity(intent);
             return true;
         }
diff --git a/src/com/owncloud/android/ui/activity/AuthenticatorActivity.java b/src/com/owncloud/android/ui/activity/AuthenticatorActivity.java
deleted file mode 100644 (file)
index 7d75e9d..0000000
+++ /dev/null
@@ -1,609 +0,0 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012  Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
- *
- *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License version 2,
- *   as published by the Free Software Foundation.
- *
- *   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 com.owncloud.android.ui.activity;
-
-import java.net.MalformedURLException;
-import java.net.URL;
-
-import com.owncloud.android.AccountUtils;
-import com.owncloud.android.Log_OC;
-import com.owncloud.android.authenticator.AccountAuthenticator;
-import com.owncloud.android.authenticator.AuthenticationRunnable;
-import com.owncloud.android.authenticator.OnAuthenticationResultListener;
-import com.owncloud.android.authenticator.OnConnectCheckListener;
-import com.owncloud.android.ui.dialog.SslValidatorDialog;
-import com.owncloud.android.ui.dialog.SslValidatorDialog.OnSslValidatorListener;
-import com.owncloud.android.network.OwnCloudClientUtils;
-import com.owncloud.android.operations.ConnectionCheckOperation;
-import com.owncloud.android.operations.OnRemoteOperationListener;
-import com.owncloud.android.operations.RemoteOperation;
-import com.owncloud.android.operations.RemoteOperationResult;
-
-import android.accounts.Account;
-import android.accounts.AccountAuthenticatorActivity;
-import android.accounts.AccountManager;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.app.ProgressDialog;
-import android.content.ContentResolver;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.preference.PreferenceManager;
-import android.text.InputType;
-import android.util.Log;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.View.OnFocusChangeListener;
-import android.view.Window;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.ImageView;
-import android.widget.TextView;
-import com.owncloud.android.R;
-
-import eu.alefzero.webdav.WebdavClient;
-
-/**
- * This Activity is used to add an ownCloud account to the App
- * 
- * @author Bartek Przybylski
- * 
- */
-public class AuthenticatorActivity extends AccountAuthenticatorActivity
-        implements OnAuthenticationResultListener, OnConnectCheckListener, OnRemoteOperationListener, OnSslValidatorListener, 
-        OnFocusChangeListener, OnClickListener {
-
-    private static final int DIALOG_LOGIN_PROGRESS = 0;
-    private static final int DIALOG_SSL_VALIDATOR = 1;
-    private static final int DIALOG_CERT_NOT_SAVED = 2;
-
-    private static final String TAG = "AuthActivity";
-
-    private Thread mAuthThread;
-    private AuthenticationRunnable mAuthRunnable;
-    //private ConnectionCheckerRunnable mConnChkRunnable = null;
-    private ConnectionCheckOperation mConnChkRunnable;
-    private final Handler mHandler = new Handler();
-    private String mBaseUrl;
-    
-    private static final String STATUS_TEXT = "STATUS_TEXT";
-    private static final String STATUS_ICON = "STATUS_ICON";
-    private static final String STATUS_CORRECT = "STATUS_CORRECT";
-    private static final String IS_SSL_CONN = "IS_SSL_CONN";
-    private int mStatusText, mStatusIcon;
-    private boolean mStatusCorrect, mIsSslConn;
-    private RemoteOperationResult mLastSslUntrustedServerResult;
-
-    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);
-        ImageView iv = (ImageView) findViewById(R.id.refreshButton);
-        ImageView iv2 = (ImageView) findViewById(R.id.viewPassword);
-        TextView tv = (TextView) findViewById(R.id.host_URL);
-        TextView tv2 = (TextView) findViewById(R.id.account_password);
-
-        if (savedInstanceState != null) {
-            mStatusIcon = savedInstanceState.getInt(STATUS_ICON);
-            mStatusText = savedInstanceState.getInt(STATUS_TEXT);
-            mStatusCorrect = savedInstanceState.getBoolean(STATUS_CORRECT);
-            mIsSslConn = savedInstanceState.getBoolean(IS_SSL_CONN);
-            setResultIconAndText(mStatusIcon, mStatusText);
-            findViewById(R.id.buttonOK).setEnabled(mStatusCorrect);
-            if (!mStatusCorrect)
-                iv.setVisibility(View.VISIBLE);
-            else
-                iv.setVisibility(View.INVISIBLE);
-
-        } else {
-            mStatusText = mStatusIcon = 0;
-            mStatusCorrect = false;
-            mIsSslConn = false;
-        }
-        iv.setOnClickListener(this);
-        iv2.setOnClickListener(this);
-        tv.setOnFocusChangeListener(this);
-        tv2.setOnFocusChangeListener(this);
-
-        Button b = (Button) findViewById(R.id.account_register);
-        if (b != null) {
-            b.setText(String.format(getString(R.string.auth_register), getString(R.string.app_name)));
-        }
-    }
-
-    @Override
-    protected void onSaveInstanceState(Bundle outState) {
-        outState.putInt(STATUS_ICON, mStatusIcon);
-        outState.putInt(STATUS_TEXT, mStatusText);
-        outState.putBoolean(STATUS_CORRECT, mStatusCorrect);
-        super.onSaveInstanceState(outState);
-    }
-
-    @Override
-    protected Dialog onCreateDialog(int id) {
-        Dialog dialog = null;
-        switch (id) {
-        case DIALOG_LOGIN_PROGRESS: {
-            ProgressDialog working_dialog = new ProgressDialog(this);
-            working_dialog.setMessage(getResources().getString(
-                    R.string.auth_trying_to_login));
-            working_dialog.setIndeterminate(true);
-            working_dialog.setCancelable(true);
-            working_dialog
-                    .setOnCancelListener(new DialogInterface.OnCancelListener() {
-                        @Override
-                        public void onCancel(DialogInterface dialog) {
-                            Log_OC.i(TAG, "Login canceled");
-                            if (mAuthThread != null) {
-                                mAuthThread.interrupt();
-                                finish();
-                            }
-                        }
-                    });
-            dialog = working_dialog;
-            break;
-        }
-        case DIALOG_SSL_VALIDATOR: {
-            dialog = SslValidatorDialog.newInstance(this, mLastSslUntrustedServerResult, this);
-            break;
-        }
-        case DIALOG_CERT_NOT_SAVED: {
-            AlertDialog.Builder builder = new AlertDialog.Builder(this);
-            builder.setMessage(getResources().getString(R.string.ssl_validator_not_saved));
-            builder.setCancelable(false);
-            builder.setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() {
-                    @Override
-                    public void onClick(DialogInterface dialog, int which) {
-                        dialog.dismiss();
-                    };
-                });
-            dialog = builder.create();
-            break;
-        }
-        default:
-            Log_OC.e(TAG, "Incorrect dialog called with id = " + id);
-        }
-        return dialog;
-    }
-
-    @Override
-    protected void onPrepareDialog(int id, Dialog dialog, Bundle args) {
-        switch (id) {
-        case DIALOG_LOGIN_PROGRESS:
-        case DIALOG_CERT_NOT_SAVED:
-            break;
-        case DIALOG_SSL_VALIDATOR: {
-            ((SslValidatorDialog)dialog).updateResult(mLastSslUntrustedServerResult);
-            break;
-        }
-        default:
-            Log_OC.e(TAG, "Incorrect dialog called with id = " + id);
-        }
-    }
-
-    public void onAuthenticationResult(boolean success, String message) {
-        if (success) {
-            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 happen
-                Log_OC.e(getClass().getName(), "Malformed URL: " + message);
-                return;
-            }
-
-            String username = username_text.getText().toString().trim();
-            String accountName = username + "@" + url.getHost();
-            if (url.getPort() >= 0) {
-                accountName += ":" + url.getPort();
-            }
-            Account account = new Account(accountName,
-                    AccountAuthenticator.ACCOUNT_TYPE);
-            AccountManager accManager = AccountManager.get(this);
-            accManager.addAccountExplicitly(account, password_text.getText()
-                    .toString(), null);
-
-            // Add this account as default in the preferences, if there is none
-            // already
-            Account defaultAccount = AccountUtils
-                    .getCurrentOwnCloudAccount(this);
-            if (defaultAccount == null) {
-                SharedPreferences.Editor editor = PreferenceManager
-                        .getDefaultSharedPreferences(this).edit();
-                editor.putString("select_oc_account", accountName);
-                editor.commit();
-            }
-
-            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);
-            intent.putExtra(AccountManager.KEY_USERDATA, username);
-
-            accManager.setUserData(account,
-                    AccountAuthenticator.KEY_OC_VERSION, mConnChkRunnable
-                            .getDiscoveredVersion().toString());
-            
-            accManager.setUserData(account,
-                    AccountAuthenticator.KEY_OC_BASE_URL, mBaseUrl);
-
-            setAccountAuthenticatorResult(intent.getExtras());
-            setResult(RESULT_OK, intent);
-            Bundle bundle = new Bundle();
-            bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
-            //getContentResolver().startSync(ProviderTableMeta.CONTENT_URI,
-            //        bundle);
-            ContentResolver.requestSync(account, "org.owncloud", bundle);
-
-            /*
-             * if
-             * (mConnChkRunnable.getDiscoveredVersion().compareTo(OwnCloudVersion
-             * .owncloud_v2) >= 0) { Intent i = new Intent(this,
-             * ExtensionsAvailableActivity.class); startActivity(i); }
-             */
-
-            finish();
-        } else {
-            try {
-                dismissDialog(DIALOG_LOGIN_PROGRESS);
-            } catch (IllegalArgumentException e) {
-                // NOTHING TO DO ; can't find out what situation that leads to the exception in this code, but user logs signal that it happens
-            }
-            TextView tv = (TextView) findViewById(R.id.account_username);
-            tv.setError(message + "        ");  // the extra spaces are a workaround for an ugly bug: 
-                                                // 1. insert wrong credentials and connect
-                                                // 2. put the focus on the user name field with using hardware controls (don't touch the screen); the error is shown UNDER the field
-                                                // 3. touch the user name field; the software keyboard appears; the error popup is moved OVER the field and SHRINKED in width, losing the last word
-                                                // Seen, at least, in Android 2.x devices
-        }
-    }
-    public void onCancelClick(View view) {
-        setResult(RESULT_CANCELED);
-        finish();
-    }
-    
-    public void onOkClick(View view) {
-        String prefix = "";
-        String url = ((TextView) findViewById(R.id.host_URL)).getText()
-                .toString().trim();
-        if (mIsSslConn) {
-            prefix = "https://";
-        } else {
-            prefix = "http://";
-        }
-        if (url.toLowerCase().startsWith("http://")
-                || url.toLowerCase().startsWith("https://")) {
-            prefix = "";
-        }
-        continueConnection(prefix);
-    }
-    
-    public void onRegisterClick(View view) {
-        Intent register = new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.url_account_register)));
-        setResult(RESULT_CANCELED);
-        startActivity(register);
-    }
-
-    private void continueConnection(String prefix) {
-        String url = ((TextView) findViewById(R.id.host_URL)).getText()
-                .toString().trim();
-        String username = ((TextView) findViewById(R.id.account_username))
-                .getText().toString();
-        String password = ((TextView) findViewById(R.id.account_password))
-                .getText().toString();
-        if (url.endsWith("/"))
-            url = url.substring(0, url.length() - 1);
-
-        URL uri = null;
-        String webdav_path = AccountUtils.getWebdavPath(mConnChkRunnable
-                .getDiscoveredVersion());
-        
-        if (webdav_path == null) {
-            onAuthenticationResult(false, getString(R.string.auth_bad_oc_version_title));
-            return;
-        }
-        
-        try {
-            mBaseUrl = prefix + url;
-            String url_str = prefix + url + webdav_path;
-            uri = new URL(url_str);
-        } catch (MalformedURLException e) {
-            // should never happen
-            onAuthenticationResult(false, getString(R.string.auth_incorrect_address_title));
-            return;
-        }
-
-        showDialog(DIALOG_LOGIN_PROGRESS);
-        mAuthRunnable = new AuthenticationRunnable(uri, username, password, this);
-        mAuthRunnable.setOnAuthenticationResultListener(this, mHandler);
-        mAuthThread = new Thread(mAuthRunnable);
-        mAuthThread.start();
-    }
-
-    @Override
-    public void onConnectionCheckResult(ResultType type) {
-        mStatusText = mStatusIcon = 0;
-        mStatusCorrect = false;
-        String t_url = ((TextView) findViewById(R.id.host_URL)).getText()
-                .toString().trim().toLowerCase();
-
-        switch (type) {
-        case OK_SSL:
-            mIsSslConn = true;
-            mStatusIcon = android.R.drawable.ic_secure;
-            mStatusText = R.string.auth_secure_connection;
-            mStatusCorrect = true;
-            break;
-        case OK_NO_SSL:
-            mIsSslConn = false;
-            mStatusCorrect = true;
-            if (t_url.startsWith("http://") ) {
-                mStatusText = R.string.auth_connection_established;
-                mStatusIcon = R.drawable.ic_ok;
-            } else {
-                mStatusText = R.string.auth_nossl_plain_ok_title;
-                mStatusIcon = android.R.drawable.ic_partial_secure;
-            }
-            break;
-        case BAD_OC_VERSION:
-            mStatusIcon = R.drawable.common_error;
-            mStatusText = R.string.auth_bad_oc_version_title;
-            break;
-        case WRONG_CONNECTION:
-            mStatusIcon = R.drawable.common_error;
-            mStatusText = R.string.auth_wrong_connection_title;
-            break;
-        case TIMEOUT:
-            mStatusIcon = R.drawable.common_error;
-            mStatusText = R.string.auth_timeout_title;
-            break;
-        case INCORRECT_ADDRESS:
-            mStatusIcon = R.drawable.common_error;
-            mStatusText = R.string.auth_incorrect_address_title;
-            break;
-        case SSL_UNVERIFIED_SERVER:
-            mStatusIcon = R.drawable.common_error;
-            mStatusText = R.string.auth_ssl_unverified_server_title;
-            break;
-        case SSL_INIT_ERROR:
-            mStatusIcon = R.drawable.common_error;
-            mStatusText = R.string.auth_ssl_general_error_title;
-            break;
-        case HOST_NOT_AVAILABLE:
-            mStatusIcon = R.drawable.common_error;
-            mStatusText = R.string.auth_unknown_host_title;
-            break;
-        case NO_NETWORK_CONNECTION:
-            mStatusIcon = R.drawable.no_network;
-            mStatusText = R.string.auth_no_net_conn_title;
-            break;
-        case INSTANCE_NOT_CONFIGURED:
-            mStatusIcon = R.drawable.common_error;
-            mStatusText = R.string.auth_not_configured_title;
-            break;
-        case UNKNOWN_ERROR:
-            mStatusIcon = R.drawable.common_error;
-            mStatusText = R.string.auth_unknown_error_title;
-            break;
-        case FILE_NOT_FOUND:
-            mStatusIcon = R.drawable.common_error;
-            mStatusText = R.string.auth_incorrect_path_title;
-            break;
-        default:
-            Log_OC.e(TAG, "Incorrect connection checker result type: " + type);
-        }
-        setResultIconAndText(mStatusIcon, mStatusText);
-        if (!mStatusCorrect)
-            findViewById(R.id.refreshButton).setVisibility(View.VISIBLE);
-        else
-            findViewById(R.id.refreshButton).setVisibility(View.INVISIBLE);
-        findViewById(R.id.buttonOK).setEnabled(mStatusCorrect);
-    }
-
-    @Override
-    public void onFocusChange(View view, boolean hasFocus) {
-        if (view.getId() == R.id.host_URL) {
-            if (!hasFocus) {
-                TextView tv = ((TextView) findViewById(R.id.host_URL));
-                String uri = tv.getText().toString().trim();
-                if (uri.length() != 0) {
-                    setResultIconAndText(R.drawable.progress_small,
-                            R.string.auth_testing_connection);
-                    //mConnChkRunnable = new ConnectionCheckerRunnable(uri, this);
-                    mConnChkRunnable = new ConnectionCheckOperation(uri, this);
-                    //mConnChkRunnable.setListener(this, mHandler);
-                    //mAuthThread = new Thread(mConnChkRunnable);
-                    //mAuthThread.start();
-                       WebdavClient client = OwnCloudClientUtils.createOwnCloudClient(Uri.parse(uri), this);
-                    mAuthThread = mConnChkRunnable.execute(client, this, mHandler);
-                } else {
-                    findViewById(R.id.refreshButton).setVisibility(
-                            View.INVISIBLE);
-                    setResultIconAndText(0, 0);
-                }
-            } else {
-                // avoids that the 'connect' button can be clicked if the test was previously passed
-                findViewById(R.id.buttonOK).setEnabled(false); 
-            }
-        } else if (view.getId() == R.id.account_password) {
-            ImageView iv = (ImageView) findViewById(R.id.viewPassword);
-            if (hasFocus) {
-                iv.setVisibility(View.VISIBLE);
-            } else {
-                TextView v = (TextView) findViewById(R.id.account_password);
-                int input_type = InputType.TYPE_CLASS_TEXT
-                        | InputType.TYPE_TEXT_VARIATION_PASSWORD;
-                v.setInputType(input_type);
-                iv.setVisibility(View.INVISIBLE);
-            }
-        }
-    }
-
-    private void setResultIconAndText(int drawable_id, int text_id) {
-        ImageView iv = (ImageView) findViewById(R.id.action_indicator);
-        TextView tv = (TextView) findViewById(R.id.status_text);
-
-        if (drawable_id == 0 && text_id == 0) {
-            iv.setVisibility(View.INVISIBLE);
-            tv.setVisibility(View.INVISIBLE);
-        } else {
-            iv.setImageResource(drawable_id);
-            tv.setText(text_id);
-            iv.setVisibility(View.VISIBLE);
-            tv.setVisibility(View.VISIBLE);
-        }
-    }
-
-    @Override
-    public void onClick(View v) {
-        if (v.getId() == R.id.refreshButton) {
-            onFocusChange(findViewById(R.id.host_URL), false);
-        } else if (v.getId() == R.id.viewPassword) {
-            EditText view = (EditText) findViewById(R.id.account_password);
-            int selectionStart = view.getSelectionStart();
-            int selectionEnd = view.getSelectionEnd();
-            int input_type = view.getInputType();
-            if ((input_type & InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) == InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) {
-                input_type = InputType.TYPE_CLASS_TEXT
-                        | InputType.TYPE_TEXT_VARIATION_PASSWORD;
-            } else {
-                input_type = InputType.TYPE_CLASS_TEXT
-                        | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD;
-            }
-            view.setInputType(input_type);
-            view.setSelection(selectionStart, selectionEnd);
-        }
-    }
-
-       @Override
-       public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationResult result) {
-               if (operation.equals(mConnChkRunnable)) {
-                   
-               mStatusText = mStatusIcon = 0;
-               mStatusCorrect = false;
-               String t_url = ((TextView) findViewById(R.id.host_URL)).getText()
-                       .toString().trim().toLowerCase();
-               
-               switch (result.getCode()) {
-               case OK_SSL:
-                   mIsSslConn = true;
-                   mStatusIcon = android.R.drawable.ic_secure;
-                   mStatusText = R.string.auth_secure_connection;
-                   mStatusCorrect = true;
-                   break;
-                   
-               case OK_NO_SSL:
-               case OK:
-                   mIsSslConn = false;
-                   mStatusCorrect = true;
-                   if (t_url.startsWith("http://") ) {
-                       mStatusText = R.string.auth_connection_established;
-                       mStatusIcon = R.drawable.ic_ok;
-                   } else {
-                       mStatusText = R.string.auth_nossl_plain_ok_title;
-                       mStatusIcon = android.R.drawable.ic_partial_secure;
-                   }
-                   break;
-               
-                   
-               case BAD_OC_VERSION:
-                   mStatusIcon = R.drawable.common_error;
-                   mStatusText = R.string.auth_bad_oc_version_title;
-                   break;
-               case WRONG_CONNECTION:
-                   mStatusIcon = R.drawable.common_error;
-                   mStatusText = R.string.auth_wrong_connection_title;
-                   break;
-               case TIMEOUT:
-                   mStatusIcon = R.drawable.common_error;
-                   mStatusText = R.string.auth_timeout_title;
-                   break;
-               case INCORRECT_ADDRESS:
-                   mStatusIcon = R.drawable.common_error;
-                   mStatusText = R.string.auth_incorrect_address_title;
-                   break;
-                   
-            case SSL_RECOVERABLE_PEER_UNVERIFIED:
-                mStatusIcon = R.drawable.common_error;
-                mStatusText = R.string.auth_ssl_unverified_server_title;
-                mLastSslUntrustedServerResult = result;
-                showDialog(DIALOG_SSL_VALIDATOR); 
-                break;
-                   
-            case SSL_ERROR:
-                mStatusIcon = R.drawable.common_error;
-                mStatusText = R.string.auth_ssl_general_error_title;
-                break;
-                
-               case HOST_NOT_AVAILABLE:
-                   mStatusIcon = R.drawable.common_error;
-                   mStatusText = R.string.auth_unknown_host_title;
-                   break;
-               case NO_NETWORK_CONNECTION:
-                   mStatusIcon = R.drawable.no_network;
-                   mStatusText = R.string.auth_no_net_conn_title;
-                   break;
-               case INSTANCE_NOT_CONFIGURED:
-                   mStatusIcon = R.drawable.common_error;
-                   mStatusText = R.string.auth_not_configured_title;
-                   break;
-               case FILE_NOT_FOUND:
-                   mStatusIcon = R.drawable.common_error;
-                   mStatusText = R.string.auth_incorrect_path_title;
-                   break;
-            case UNHANDLED_HTTP_CODE:
-            case UNKNOWN_ERROR:
-                mStatusIcon = R.drawable.common_error;
-                mStatusText = R.string.auth_unknown_error_title;
-                break;
-               default:
-                   Log_OC.e(TAG, "Incorrect connection checker result type: " + result.getHttpCode());
-               }
-               setResultIconAndText(mStatusIcon, mStatusText);
-               if (!mStatusCorrect)
-                   findViewById(R.id.refreshButton).setVisibility(View.VISIBLE);
-               else
-                   findViewById(R.id.refreshButton).setVisibility(View.INVISIBLE);
-               findViewById(R.id.buttonOK).setEnabled(mStatusCorrect);
-               }
-       }
-
-       
-    public void onSavedCertificate() {
-        mAuthThread = mConnChkRunnable.retry(this, mHandler);                
-    }
-
-    @Override
-    public void onFailedSavingCertificate() {
-        showDialog(DIALOG_CERT_NOT_SAVED);
-    }
-    
-}
index 5ac6df9..d61626c 100644 (file)
@@ -28,7 +28,6 @@ import android.os.Bundle;
 import android.os.Handler;
 import android.support.v4.app.DialogFragment;
 import android.text.method.ScrollingMovementMethod;
-import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.OnClickListener;
index e468ffb..4c13fb2 100644 (file)
@@ -1,3 +1,20 @@
+/* ownCloud Android client application\r
+ *   Copyright (C) 2012-2013 ownCloud Inc.\r
+ *\r
+ *   This program is free software: you can redistribute it and/or modify\r
+ *   it under the terms of the GNU General Public License version 2,\r
+ *   as published by the Free Software Foundation.\r
+ *\r
+ *   This program is distributed in the hope that it will be useful,\r
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ *   GNU General Public License for more details.\r
+ *\r
+ *   You should have received a copy of the GNU General Public License\r
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.\r
+ *\r
+ */\r
+\r
 package com.owncloud.android.ui.activity;\r
 \r
 import android.app.Activity;\r
@@ -14,18 +31,7 @@ import com.owncloud.android.R;
  * \r
  * The entry-point for this activity is the 'Failed upload Notification"\r
  * \r
- * \r
  * @author andomaex / Matthias Baumann\r
- * \r
- *         This program is free software: you can redistribute it and/or modify\r
- *         it under the terms of the GNU General Public License as published by\r
- *         the Free Software Foundation, either version 3 of the License. (at\r
- *         your option) any later version.\r
- * \r
- *         This program is distributed in the hope that it will be useful, but\r
- *         WITHOUT ANY WARRANTY; without even the implied warranty of\r
- *         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
- *         General Public License for more de/\r
  */\r
 public class FailedUploadActivity extends Activity {\r
 \r
index 711b07a..4cd9363 100644 (file)
@@ -31,7 +31,6 @@ import android.os.Bundle;
 import android.os.IBinder;
 import android.support.v4.app.Fragment;
 import android.support.v4.app.FragmentTransaction;
-import android.util.Log;
 
 import com.actionbarsherlock.app.ActionBar;
 import com.actionbarsherlock.app.SherlockFragmentActivity;
index 88dd728..6fd51a9 100644 (file)
@@ -23,7 +23,6 @@ import java.io.File;
 import android.accounts.Account;
 import android.app.AlertDialog;
 import android.app.ProgressDialog;
-import android.app.AlertDialog.Builder;
 import android.app.Dialog;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -35,8 +34,6 @@ import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
 import android.content.SharedPreferences;
-import android.content.SharedPreferences.Editor;
-import android.content.pm.PackageInfo;
 import android.content.res.Resources.NotFoundException;
 import android.database.Cursor;
 import android.net.Uri;
@@ -47,11 +44,9 @@ import android.preference.PreferenceManager;
 import android.provider.MediaStore;
 import android.support.v4.app.Fragment;
 import android.support.v4.app.FragmentTransaction;
-import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ArrayAdapter;
-import android.widget.EditText;
 import android.widget.TextView;
 import android.widget.Toast;
 
@@ -65,7 +60,7 @@ import com.actionbarsherlock.view.Window;
 import com.owncloud.android.AccountUtils;
 import com.owncloud.android.Log_OC;
 import com.owncloud.android.R;
-import com.owncloud.android.authenticator.AccountAuthenticator;
+import com.owncloud.android.authentication.AccountAuthenticator;
 import com.owncloud.android.datamodel.DataStorageManager;
 import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
@@ -74,7 +69,7 @@ import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
 import com.owncloud.android.files.services.FileObserverService;
 import com.owncloud.android.files.services.FileUploader;
 import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
-import com.owncloud.android.network.OwnCloudClientUtils;
+import com.owncloud.android.operations.CreateFolderOperation;
 import com.owncloud.android.operations.OnRemoteOperationListener;
 import com.owncloud.android.operations.RemoteOperation;
 import com.owncloud.android.operations.RemoteOperationResult;
@@ -83,7 +78,6 @@ import com.owncloud.android.operations.RenameFileOperation;
 import com.owncloud.android.operations.SynchronizeFileOperation;
 import com.owncloud.android.operations.RemoteOperationResult.ResultCode;
 import com.owncloud.android.syncadapter.FileSyncService;
-import com.owncloud.android.ui.dialog.ChangelogDialog;
 import com.owncloud.android.ui.dialog.EditNameDialog;
 import com.owncloud.android.ui.dialog.SslValidatorDialog;
 import com.owncloud.android.ui.dialog.EditNameDialog.EditNameDialogListener;
@@ -95,8 +89,6 @@ import com.owncloud.android.ui.preview.PreviewImageActivity;
 import com.owncloud.android.ui.preview.PreviewImageFragment;
 import com.owncloud.android.ui.preview.PreviewMediaFragment;
 
-import eu.alefzero.webdav.WebdavClient;
-
 /**
  * Displays, what files the user has available in his ownCloud.
  * 
@@ -126,13 +118,10 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
     private boolean mBackFromCreatingFirstAccount;
     
     private static final int DIALOG_SETUP_ACCOUNT = 0;
-    private static final int DIALOG_CREATE_DIR = 1;
-    public static final int DIALOG_SHORT_WAIT = 3;
-    private static final int DIALOG_CHOOSE_UPLOAD_SOURCE = 4;
-    private static final int DIALOG_SSL_VALIDATOR = 5;
-    private static final int DIALOG_CERT_NOT_SAVED = 6;
-    private static final String DIALOG_CHANGELOG_TAG = "DIALOG_CHANGELOG";
-
+    public static final int DIALOG_SHORT_WAIT = 1;
+    private static final int DIALOG_CHOOSE_UPLOAD_SOURCE = 2;
+    private static final int DIALOG_SSL_VALIDATOR = 3;
+    private static final int DIALOG_CERT_NOT_SAVED = 4;
     
     private static final int ACTION_SELECT_CONTENT_FROM_APPS = 1;
     private static final int ACTION_SELECT_MULTIPLE_FILES = 2;
@@ -147,6 +136,8 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
         Log_OC.d(getClass().toString(), "onCreate() start");
         super.onCreate(savedInstanceState);
 
+        mHandler = new Handler();
+
         /// Load of parameters from received intent
         Account account = getIntent().getParcelableExtra(FileDetailFragment.EXTRA_ACCOUNT);
         if (account != null && AccountUtils.setCurrentOwnCloudAccount(this, account.name)) {
@@ -233,8 +224,6 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
         setSupportProgressBarIndeterminateVisibility(false);        // always AFTER setContentView(...) ; to workaround bug in its implementation
         
         
-        // show changelog, if needed
-        //showChangeLog();
         mBackFromCreatingFirstAccount = false;
         
         Log_OC.d(getClass().toString(), "onCreate() end");
@@ -242,37 +231,11 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
 
     
     /**
-     * Shows a dialog with the change log of the current version after each app update
-     * 
-     *  TODO make it permanent; by now, only to advice the workaround app for 4.1.x
-     */
-    private void showChangeLog() {
-        if (android.os.Build.VERSION.SDK_INT == android.os.Build.VERSION_CODES.JELLY_BEAN) {
-            final String KEY_VERSION = "version";
-            SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
-            int currentVersionNumber = 0;
-            int savedVersionNumber = sharedPref.getInt(KEY_VERSION, 0);
-            try {
-                PackageInfo pi          = getPackageManager().getPackageInfo(getPackageName(), 0);
-                currentVersionNumber    = pi.versionCode;
-            } catch (Exception e) {}
-     
-            if (currentVersionNumber > savedVersionNumber) {
-                ChangelogDialog.newInstance(true).show(getSupportFragmentManager(), DIALOG_CHANGELOG_TAG);
-                Editor editor   = sharedPref.edit();
-                editor.putInt(KEY_VERSION, currentVersionNumber);
-                editor.commit();
-            }
-        }
-    }
-    
-
-    /**
      * Launches the account creation activity. To use when no ownCloud account is available
      */
     private void createFirstAccount() {
         Intent intent = new Intent(android.provider.Settings.ACTION_ADD_ACCOUNT);
-        intent.putExtra(android.provider.Settings.EXTRA_AUTHORITIES, new String[] { AccountAuthenticator.AUTH_TOKEN_TYPE });
+        intent.putExtra(android.provider.Settings.EXTRA_AUTHORITIES, new String[] { AccountAuthenticator.AUTHORITY });
         startActivity(intent);  // the new activity won't be created until this.onStart() and this.onResume() are finished;
     }
 
@@ -386,12 +349,12 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
     }
 
     private void startSynchronization() {
-        ContentResolver.cancelSync(null, AccountAuthenticator.AUTH_TOKEN_TYPE);   // cancel the current synchronizations of any ownCloud account
+        ContentResolver.cancelSync(null, AccountAuthenticator.AUTHORITY);   // cancel the current synchronizations of any ownCloud account
         Bundle bundle = new Bundle();
         bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
         ContentResolver.requestSync(
                 AccountUtils.getCurrentOwnCloudAccount(this),
-                AccountAuthenticator.AUTH_TOKEN_TYPE, bundle);
+                AccountAuthenticator.AUTHORITY, bundle);
     }
 
 
@@ -545,7 +508,6 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
         outState.putParcelable(FileDetailActivity.KEY_WAITING_TO_PREVIEW, mWaitingToPreview);
         Log_OC.d(getClass().toString(), "onSaveInstanceState() end");
     }
-
     
     @Override
     protected void onResume() {
@@ -651,53 +613,6 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
             dialog = builder.create();
             break;
         }
-        case DIALOG_CREATE_DIR: {
-            builder = new Builder(this);
-            final EditText dirNameInput = new EditText(getBaseContext());
-            builder.setView(dirNameInput);
-            builder.setTitle(R.string.uploader_info_dirname);
-            int typed_color = getResources().getColor(R.color.setup_text_typed);
-            dirNameInput.setTextColor(typed_color);
-            builder.setPositiveButton(android.R.string.ok,
-                    new OnClickListener() {
-                        public void onClick(DialogInterface dialog, int which) {
-                            String directoryName = dirNameInput.getText().toString();
-                            if (directoryName.trim().length() == 0) {
-                                dialog.cancel();
-                                return;
-                            }
-    
-                            // Figure out the path where the dir needs to be created
-                            String path;
-                            if (mCurrentDir == null) {
-                                // this is just a patch; we should ensure that mCurrentDir never is null
-                                if (!mStorageManager.fileExists(OCFile.PATH_SEPARATOR)) {
-                                    OCFile file = new OCFile(OCFile.PATH_SEPARATOR);
-                                    mStorageManager.saveFile(file);
-                                }
-                                mCurrentDir = mStorageManager.getFileByPath(OCFile.PATH_SEPARATOR);
-                            }
-                            path = FileDisplayActivity.this.mCurrentDir.getRemotePath();
-                            
-                            // Create directory
-                            path += directoryName + OCFile.PATH_SEPARATOR;
-                            Thread thread = new Thread(new DirectoryCreator(path,  AccountUtils.getCurrentOwnCloudAccount(FileDisplayActivity.this), new Handler()));
-                            thread.start();
-                            
-                            dialog.dismiss();
-                            
-                            showDialog(DIALOG_SHORT_WAIT);
-                        }
-                    });
-            builder.setNegativeButton(R.string.common_cancel,
-                    new OnClickListener() {
-                        public void onClick(DialogInterface dialog, int which) {
-                            dialog.cancel();
-                        }
-                    });
-            dialog = builder.create();
-            break;
-        }
         case DIALOG_SHORT_WAIT: {
             ProgressDialog working_dialog = new ProgressDialog(this);
             working_dialog.setMessage(getResources().getString(
@@ -818,57 +733,6 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
         return !mDirectories.isEmpty();
     }
 
-    private class DirectoryCreator implements Runnable {
-        private String mTargetPath;
-        private Account mAccount;
-        private Handler mHandler; 
-    
-        public DirectoryCreator(String targetPath, Account account, Handler handler) {
-            mTargetPath = targetPath;
-            mAccount = account;
-            mHandler = handler;
-        }
-    
-        @Override
-        public void run() {
-            WebdavClient wdc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getApplicationContext());
-            boolean created = wdc.createDirectory(mTargetPath);
-            if (created) {
-                mHandler.post(new Runnable() {
-                    @Override
-                    public void run() { 
-                        dismissDialog(DIALOG_SHORT_WAIT);
-                        
-                        // Save new directory in local database
-                        OCFile newDir = new OCFile(mTargetPath);
-                        newDir.setMimetype("DIR");
-                        newDir.setParentId(mCurrentDir.getFileId());
-                        mStorageManager.saveFile(newDir);
-    
-                        // Display the new folder right away
-                        mFileList.listDirectory();
-                    }
-                });
-                
-            } else {
-                mHandler.post(new Runnable() {
-                    @Override
-                    public void run() {
-                        dismissDialog(DIALOG_SHORT_WAIT);
-                        try {
-                            Toast msg = Toast.makeText(FileDisplayActivity.this, R.string.create_dir_fail_msg, Toast.LENGTH_LONG); 
-                            msg.show();
-                        
-                        } catch (NotFoundException e) {
-                            Log_OC.e(TAG, "Error while trying to show fail message ", e);
-                        }
-                    }
-                });
-            }
-        }
-    
-    }
-
     // Custom array adapter to override text colors
     private class CustomArrayAdapter<T> extends ArrayAdapter<T> {
     
@@ -1283,6 +1147,9 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
             
         } else if (operation instanceof SynchronizeFileOperation) {
             onSynchronizeFileOperationFinish((SynchronizeFileOperation)operation, result);
+
+        } else if (operation instanceof CreateFolderOperation) {
+            onCreateFolderOperationFinish((CreateFolderOperation)operation, result);
         }
     }
 
@@ -1323,6 +1190,30 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
     }
 
     /**
+     * Updates the view associated to the activity after the finish of an operation trying create a new folder
+     * 
+     * @param operation     Creation operation performed.
+     * @param result        Result of the creation.
+     */
+    private void onCreateFolderOperationFinish(CreateFolderOperation operation, RemoteOperationResult result) {
+        if (result.isSuccess()) {
+            dismissDialog(DIALOG_SHORT_WAIT);
+            mFileList.listDirectory();
+            
+        } else {
+            dismissDialog(DIALOG_SHORT_WAIT);
+            try {
+                Toast msg = Toast.makeText(FileDisplayActivity.this, R.string.create_dir_fail_msg, Toast.LENGTH_LONG); 
+                msg.show();
+                    
+            } catch (NotFoundException e) {
+                Log_OC.e(TAG, "Error while trying to show fail message " , e);
+            }
+        }
+    }
+    
+    
+    /**
      * Updates the view associated to the activity after the finish of an operation trying to rename a 
      * file. 
      * 
@@ -1430,7 +1321,7 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
         //dialog.dismiss();
         if (dialog.getResult()) {
             String newDirectoryName = dialog.getNewFilename().trim();
-            Log.d(TAG, "'create directory' dialog dismissed with new name " + newDirectoryName);
+            Log_OC.d(TAG, "'create directory' dialog dismissed with new name " + newDirectoryName);
             if (newDirectoryName.length() > 0) {
                 String path;
                 if (mCurrentDir == null) {
@@ -1445,14 +1336,19 @@ public class FileDisplayActivity extends SherlockFragmentActivity implements
                 
                 // Create directory
                 path += newDirectoryName + OCFile.PATH_SEPARATOR;
-                Thread thread = new Thread(new DirectoryCreator(path,  AccountUtils.getCurrentOwnCloudAccount(FileDisplayActivity.this), new Handler()));
-                thread.start();
+                RemoteOperation operation = new CreateFolderOperation(path, mCurrentDir.getFileId(), mStorageManager);
+                operation.execute(  AccountUtils.getCurrentOwnCloudAccount(FileDisplayActivity.this), 
+                                    FileDisplayActivity.this, 
+                                    FileDisplayActivity.this, 
+                                    mHandler,
+                                    FileDisplayActivity.this);
                 
                 showDialog(DIALOG_SHORT_WAIT);
             }
         }
     }
-
+    
+    
     private void requestForDownload() {
         Account account = AccountUtils.getCurrentOwnCloudAccount(this);
         if (!mDownloaderBinder.isDownloading(account, mWaitingToPreview)) {
index 8f34327..99b0b83 100644 (file)
@@ -2,8 +2,8 @@
  *   Copyright (C) 2012-2013 ownCloud Inc.
  *
  *   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.
+ *   it under the terms of the GNU General Public License version 2,
+ *   as published by the Free Software Foundation.
  *
  *   This program is distributed in the hope that it will be useful,
  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -26,7 +26,6 @@ import android.database.Cursor;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.os.Bundle;
-import android.util.Log;
 import android.util.SparseArray;
 import android.view.Gravity;
 import android.view.View;
@@ -59,16 +58,6 @@ import com.owncloud.android.utils.FileStorageUtils;
  * sub-menu underneath the 'Upload' menu-item
  * 
  * @author andomaex / Matthias Baumann
- * 
- *         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. (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 de/
  */
 public class InstantUploadActivity extends Activity {
 
@@ -363,7 +352,7 @@ public class InstantUploadActivity extends Activity {
 
             @Override
             public boolean onLongClick(View v) {
-                Log.d(LOG_TAG, message);
+                Log_OC.d(LOG_TAG, message);
                 Toast toast = Toast.makeText(InstantUploadActivity.this, getString(R.string.failed_upload_retry_text)
                         + message, Toast.LENGTH_LONG);
                 toast.show();
index 7ae0e00..8540bb2 100644 (file)
@@ -17,7 +17,7 @@
 package com.owncloud.android.ui.activity;\r
 \r
 import com.actionbarsherlock.app.SherlockFragmentActivity;\r
-import com.owncloud.android.authenticator.AccountAuthenticator;\r
+import com.owncloud.android.authentication.AccountAuthenticator;\r
 import com.owncloud.android.ui.adapter.LandingScreenAdapter;\r
 \r
 import android.accounts.Account;\r
@@ -112,9 +112,9 @@ public class LandingActivity extends SherlockFragmentActivity implements
         dialog.dismiss();\r
         switch (which) {\r
         case DialogInterface.BUTTON_POSITIVE:\r
-            Intent intent = new Intent("android.settings.ADD_ACCOUNT_SETTINGS");\r
+            Intent intent = new Intent(android.provider.Settings.ACTION_ADD_ACCOUNT);\r
             intent.putExtra("authorities",\r
-                    new String[] { AccountAuthenticator.AUTH_TOKEN_TYPE });\r
+                    new String[] { AccountAuthenticator.AUTHORITY });\r
             startActivity(intent);\r
             break;\r
         case DialogInterface.BUTTON_NEGATIVE:\r
index 8a62219..16e05f8 100644 (file)
@@ -25,7 +25,6 @@ import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.Environment;
 import android.support.v4.app.DialogFragment;
-import android.util.Log;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.ViewGroup;
index 16e390d..a5766ee 100644 (file)
@@ -31,7 +31,6 @@ import javax.security.auth.x500.X500Principal;
 import android.app.Dialog;
 import android.content.Context;
 import android.os.Bundle;
-import android.util.Log;
 import android.view.View;
 import android.view.Window;
 import android.widget.Button;
index 84a31b9..d528b34 100644 (file)
@@ -22,7 +22,6 @@ import android.app.AlertDialog;
 import android.app.Dialog;
 import android.content.DialogInterface;
 import android.os.Bundle;
-import android.util.Log;
 
 import com.actionbarsherlock.app.SherlockDialogFragment;
 import com.owncloud.android.Log_OC;
index 32d8f9a..ec20f86 100644 (file)
@@ -19,24 +19,8 @@ package com.owncloud.android.ui.fragment;
 
 import java.io.File;
 import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.commons.httpclient.methods.GetMethod;
-import org.apache.commons.httpclient.methods.PostMethod;
-import org.apache.commons.httpclient.methods.StringRequestEntity;
-import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
-import org.apache.http.HttpStatus;
-import org.apache.http.NameValuePair;
-import org.apache.http.client.utils.URLEncodedUtils;
-import org.apache.http.message.BasicNameValuePair;
-import org.apache.http.protocol.HTTP;
-import org.apache.jackrabbit.webdav.client.methods.PropFindMethod;
-import org.json.JSONObject;
 
 import android.accounts.Account;
-import android.accounts.AccountManager;
-//import android.annotation.SuppressLint;
 import android.app.Activity;
 import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
@@ -47,7 +31,6 @@ import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
 import android.support.v4.app.FragmentTransaction;
-import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.OnClickListener;
@@ -60,42 +43,15 @@ import android.widget.ProgressBar;
 import android.widget.TextView;
 import android.widget.Toast;
 
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.BitmapFactory.Options;
-import android.graphics.Point;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.os.Handler;
-import android.support.v4.app.DialogFragment;
-import android.support.v4.app.FragmentTransaction;
-import android.util.Log;
-import android.view.Display;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.ViewGroup;
-import android.webkit.MimeTypeMap;
-import android.widget.Button;
-import android.widget.CheckBox;
-import android.widget.ImageView;
-import android.widget.TextView;
-import android.widget.Toast;
-
-
 import com.actionbarsherlock.app.SherlockFragment;
-import com.owncloud.android.AccountUtils;
 import com.owncloud.android.DisplayUtils;
 import com.owncloud.android.Log_OC;
-import com.owncloud.android.authenticator.AccountAuthenticator;
 import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.files.services.FileObserverService;
 import com.owncloud.android.files.services.FileUploader;
 import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
 import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
-import com.owncloud.android.network.OwnCloudClientUtils;
 import com.owncloud.android.operations.OnRemoteOperationListener;
 import com.owncloud.android.operations.RemoteOperation;
 import com.owncloud.android.operations.RemoteOperationResult;
@@ -108,15 +64,12 @@ import com.owncloud.android.ui.activity.FileDetailActivity;
 import com.owncloud.android.ui.activity.FileDisplayActivity;
 import com.owncloud.android.ui.dialog.EditNameDialog;
 import com.owncloud.android.ui.dialog.EditNameDialog.EditNameDialogListener;
-import com.owncloud.android.utils.OwnCloudVersion;
 
 import com.owncloud.android.R;
 
 import eu.alefzero.webdav.OnDatatransferProgressListener;
-import eu.alefzero.webdav.WebdavClient;
 import eu.alefzero.webdav.WebdavUtils;
 
-
 /**
  * This Fragment is used to display the details about a file.
  * 
@@ -163,7 +116,6 @@ public class FileDetailFragment extends SherlockFragment implements
         mProgressListener = null;
     }
     
-    
     /**
      * Creates a details fragment.
      * 
@@ -289,57 +241,58 @@ public class FileDetailFragment extends SherlockFragment implements
     }
 
     
-    @Override
-    public View getView() {
-        return super.getView() == null ? mView : super.getView();
-    }
-
-    @Override
-    public void onClick(View v) {
-        switch (v.getId()) {
-            case R.id.fdDownloadBtn: {
-                FileDownloaderBinder downloaderBinder = mContainerActivity.getFileDownloaderBinder();
-                FileUploaderBinder uploaderBinder = mContainerActivity.getFileUploaderBinder();
-                if (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, mFile)) {
-                    downloaderBinder.cancel(mAccount, mFile);
-                    if (mFile.isDown()) {
-                        setButtonsForDown();
-                    } else {
-                        setButtonsForRemote();
-                    }
-
-                } else if (uploaderBinder != null && uploaderBinder.isUploading(mAccount, mFile)) {
-                    uploaderBinder.cancel(mAccount, mFile);
-                    if (!mFile.fileExists()) {
-                        // TODO make something better
-                        if (getActivity() instanceof FileDisplayActivity) {
-                            // double pane
-                            FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction();
-                            transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null), FTAG); // empty FileDetailFragment
-                            transaction.commit();
-                            mContainerActivity.onFileStateChanged();
-                        } else {
-                            getActivity().finish();
-                        }
-                        
-                    } else if (mFile.isDown()) {
-                        setButtonsForDown();
-                    } else {
-                        setButtonsForRemote();
-                    }
-                    
-                } else {
-                    mLastRemoteOperation = new SynchronizeFileOperation(mFile, null, mStorageManager, mAccount, true, false, getActivity());
-                    WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getSherlockActivity().getApplicationContext());
-                    mLastRemoteOperation.execute(wc, this, mHandler);
-                
-                    // update ui 
-                    boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;
-                    getActivity().showDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);
-                    
-                }
-                break;
-            }
+    @Override\r
+    public View getView() {\r
+        return super.getView() == null ? mView : super.getView();\r
+    }\r
+
+    \r
+    @Override\r
+    public void onClick(View v) {\r
+        switch (v.getId()) {\r
+            case R.id.fdDownloadBtn: {\r
+                FileDownloaderBinder downloaderBinder = mContainerActivity.getFileDownloaderBinder();\r
+                FileUploaderBinder uploaderBinder = mContainerActivity.getFileUploaderBinder();\r
+                if (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, mFile)) {\r
+                    downloaderBinder.cancel(mAccount, mFile);\r
+                    if (mFile.isDown()) {\r
+                        setButtonsForDown();\r
+                    } else {\r
+                        setButtonsForRemote();\r
+                    }\r
+\r
+                } else if (uploaderBinder != null && uploaderBinder.isUploading(mAccount, mFile)) {\r
+                    uploaderBinder.cancel(mAccount, mFile);\r
+                    if (!mFile.fileExists()) {\r
+                        // TODO make something better\r
+                        if (getActivity() instanceof FileDisplayActivity) {\r
+                            // double pane\r
+                            FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction();\r
+                            transaction.replace(R.id.file_details_container, new FileDetailFragment(null, null), FTAG); // empty FileDetailFragment\r
+                            transaction.commit();\r
+                            mContainerActivity.onFileStateChanged();\r
+                        } else {\r
+                            getActivity().finish();\r
+                        }\r
+                        \r
+                    } else if (mFile.isDown()) {\r
+                        setButtonsForDown();\r
+                    } else {\r
+                        setButtonsForRemote();\r
+                    }\r
+                    \r
+                } else {\r
+                    mLastRemoteOperation = new SynchronizeFileOperation(mFile, null, mStorageManager, mAccount, true, false, getActivity());\r
+                    mLastRemoteOperation.execute(mAccount, getSherlockActivity(), this, mHandler, getSherlockActivity());\r
+                \r
+                    // update ui \r
+                    boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;\r
+                    getActivity().showDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);\r
+                    setButtonsForTransferring(); // disable button immediately, although the synchronization does not result in a file transference\r
+                    \r
+                }\r
+                break;\r
+            }\r
             case R.id.fdKeepInSync: {
                 CheckBox cb = (CheckBox) getView().findViewById(R.id.fdKeepInSync);
                 mFile.setKeepInSync(cb.isChecked());
@@ -389,13 +342,8 @@ public class FileDetailFragment extends SherlockFragment implements
                 Log_OC.e(TAG, "Incorrect view clicked!");
         }
         
-        /* else if (v.getId() == R.id.fdShareBtn) {
-            Thread t = new Thread(new ShareRunnable(mFile.getRemotePath()));
-            t.start();
-        }*/
-    }
-    
-    
+    }\r
+    \r
     /**
      * Opens mFile.
      */
@@ -410,7 +358,7 @@ public class FileDetailFragment extends SherlockFragment implements
             startActivity(i);
             
         } catch (Throwable t) {
-            Log.e(TAG, "Fail when trying to open with the mimeType provided from the ownCloud server: " + mFile.getMimetype());
+            Log_OC.e(TAG, "Fail when trying to open with the mimeType provided from the ownCloud server: " + mFile.getMimetype());
             boolean toastIt = true; 
             String mimeType = "";
             try {
@@ -429,13 +377,13 @@ public class FileDetailFragment extends SherlockFragment implements
                 }
                 
             } catch (IndexOutOfBoundsException e) {
-                Log.e(TAG, "Trying to find out MIME type of a file without extension: " + storagePath);
+                Log_OC.e(TAG, "Trying to find out MIME type of a file without extension: " + storagePath);
                 
             } catch (ActivityNotFoundException e) {
-                Log.e(TAG, "No activity found to handle: " + storagePath + " with MIME type " + mimeType + " obtained from extension");
+                Log_OC.e(TAG, "No activity found to handle: " + storagePath + " with MIME type " + mimeType + " obtained from extension");
                 
             } catch (Throwable th) {
-                Log.e(TAG, "Unexpected problem when opening: " + storagePath, th);
+                Log_OC.e(TAG, "Unexpected problem when opening: " + storagePath, th);
                 
             } finally {
                 if (toastIt) {
@@ -446,7 +394,6 @@ public class FileDetailFragment extends SherlockFragment implements
         }
     }
 
-
     @Override
     public void onConfirmation(String callerTag) {
         if (callerTag.equals(FTAG_CONFIRMATION)) {
@@ -454,8 +401,7 @@ public class FileDetailFragment extends SherlockFragment implements
                 mLastRemoteOperation = new RemoveFileOperation( mFile, 
                                                                 true, 
                                                                 mStorageManager);
-                WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getSherlockActivity().getApplicationContext());
-                mLastRemoteOperation.execute(wc, this, mHandler);
+                mLastRemoteOperation.execute(mAccount, getSherlockActivity(), this, mHandler, getSherlockActivity());
                 
                 boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;
                 getActivity().showDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);
@@ -476,7 +422,7 @@ public class FileDetailFragment extends SherlockFragment implements
     
     @Override
     public void onCancel(String callerTag) {
-        Log.d(TAG, "REMOVAL CANCELED");
+        Log_OC.d(TAG, "REMOVAL CANCELED");
     }
     
     
@@ -567,7 +513,6 @@ public class FileDetailFragment extends SherlockFragment implements
         getView().invalidate();
     }
     
-    
     /**
      * Checks if the fragment is ready to show details of a OCFile
      *  
@@ -769,120 +714,15 @@ public class FileDetailFragment extends SherlockFragment implements
     }
     
 
-    // this is a temporary class for sharing purposes, it need to be replaced in transfer service
-    @SuppressWarnings("unused")
-    private class ShareRunnable implements Runnable {
-        private String mPath;
-
-        public ShareRunnable(String path) {
-            mPath = path;
-        }
-        
-        public void run() {
-            AccountManager am = AccountManager.get(getActivity());
-            Account account = AccountUtils.getCurrentOwnCloudAccount(getActivity());
-            OwnCloudVersion ocv = new OwnCloudVersion(am.getUserData(account, AccountAuthenticator.KEY_OC_VERSION));
-            String url = am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + AccountUtils.getWebdavPath(ocv);
-
-            Log.d("share", "sharing for version " + ocv.toString());
-
-            if (ocv.compareTo(new OwnCloudVersion(0x040000)) >= 0) {
-                String APPS_PATH = "/apps/files_sharing/";
-                String SHARE_PATH = "ajax/share.php";
-
-                String SHARED_PATH = "/apps/files_sharing/get.php?token=";
-                
-                final String WEBDAV_SCRIPT = "webdav.php";
-                final String WEBDAV_FILES_LOCATION = "/files/";
-                
-                WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(account, getActivity().getApplicationContext());
-                HttpConnectionManagerParams params = new HttpConnectionManagerParams();
-                params.setMaxConnectionsPerHost(wc.getHostConfiguration(), 5);
-
-                //wc.getParams().setParameter("http.protocol.single-cookie-header", true);
-                //wc.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY);
-
-                PostMethod post = new PostMethod(am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + APPS_PATH + SHARE_PATH);
-
-                post.addRequestHeader("Content-type","application/x-www-form-urlencoded; charset=UTF-8" );
-                post.addRequestHeader("Referer", am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL));
-                List<NameValuePair> formparams = new ArrayList<NameValuePair>();
-                Log.d("share", mPath+"");
-                formparams.add(new BasicNameValuePair("sources",mPath));
-                formparams.add(new BasicNameValuePair("uid_shared_with", "public"));
-                formparams.add(new BasicNameValuePair("permissions", "0"));
-                post.setRequestEntity(new StringRequestEntity(URLEncodedUtils.format(formparams, HTTP.UTF_8)));
-
-                int status;
-                try {
-                    PropFindMethod find = new PropFindMethod(url+"/");
-                    find.addRequestHeader("Referer", am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL));
-                    Log.d("sharer", ""+ url+"/");
-                    
-                    for (org.apache.commons.httpclient.Header a : find.getRequestHeaders()) {
-                        Log.d("sharer-h", a.getName() + ":"+a.getValue());
-                    }
-                    
-                    int status2 = wc.executeMethod(find);
-
-                    Log.d("sharer", "propstatus "+status2);
-                    
-                    GetMethod get = new GetMethod(am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + "/");
-                    get.addRequestHeader("Referer", am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL));
-                    
-                    status2 = wc.executeMethod(get);
-
-                    Log.d("sharer", "getstatus "+status2);
-                    Log.d("sharer", "" + get.getResponseBodyAsString());
-                    
-                    for (org.apache.commons.httpclient.Header a : get.getResponseHeaders()) {
-                        Log.d("sharer", a.getName() + ":"+a.getValue());
-                    }
-
-                    status = wc.executeMethod(post);
-                    for (org.apache.commons.httpclient.Header a : post.getRequestHeaders()) {
-                        Log.d("sharer-h", a.getName() + ":"+a.getValue());
-                    }
-                    for (org.apache.commons.httpclient.Header a : post.getResponseHeaders()) {
-                        Log.d("sharer", a.getName() + ":"+a.getValue());
-                    }
-                    String resp = post.getResponseBodyAsString();
-                    Log.d("share", ""+post.getURI().toString());
-                    Log.d("share", "returned status " + status);
-                    Log.d("share", " " +resp);
-                    
-                    if(status != HttpStatus.SC_OK ||resp == null || resp.equals("") || resp.startsWith("false")) {
-                        return;
-                     }
-
-                    JSONObject jsonObject = new JSONObject (resp);
-                    String jsonStatus = jsonObject.getString("status");
-                    if(!jsonStatus.equals("success")) throw new Exception("Error while sharing file status != success");
-                    
-                    String token = jsonObject.getString("data");
-                    String uri = am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + SHARED_PATH + token; 
-                    Log.d("Actions:shareFile ok", "url: " + uri);   
-                    
-                } catch (Exception e) {
-                    e.printStackTrace();
-                }
-                
-            } else if (ocv.compareTo(new OwnCloudVersion(0x030000)) >= 0) {
-                
-            }
-        }
-    }
-    
     public void onDismiss(EditNameDialog dialog) {
         if (dialog.getResult()) {
             String newFilename = dialog.getNewFilename();
-            Log.d(TAG, "name edit dialog dismissed with new name " + newFilename);
+            Log_OC.d(TAG, "name edit dialog dismissed with new name " + newFilename);
             mLastRemoteOperation = new RenameFileOperation( mFile, 
                                                             mAccount, 
                                                             newFilename, 
                                                             new FileDataStorageManager(mAccount, getActivity().getContentResolver()));
-            WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getSherlockActivity().getApplicationContext());
-            mLastRemoteOperation.execute(wc, this, mHandler);
+            mLastRemoteOperation.execute(mAccount, getSherlockActivity(), this, mHandler, getSherlockActivity());
             boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;
             getActivity().showDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);
         }
@@ -998,7 +838,7 @@ public class FileDetailFragment extends SherlockFragment implements
         }
     }
     
-    
+
     public void listenForTransferProgress() {
         if (mProgressListener != null) {
             if (mContainerActivity.getFileDownloaderBinder() != null) {
@@ -1057,4 +897,110 @@ public class FileDetailFragment extends SherlockFragment implements
 
     };
 
-}
\ No newline at end of file
+    /*
+    // this is a temporary class for sharing purposes, it need to be replaced in transfer service
+    @SuppressWarnings("unused")
+    private class ShareRunnable implements Runnable {
+        private String mPath;
+
+        public ShareRunnable(String path) {
+            mPath = path;
+        }
+        
+        public void run() {
+            AccountManager am = AccountManager.get(getActivity());
+            Account account = AccountUtils.getCurrentOwnCloudAccount(getActivity());
+            OwnCloudVersion ocv = new OwnCloudVersion(am.getUserData(account, AccountAuthenticator.KEY_OC_VERSION));
+            String url = am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + AccountUtils.getWebdavPath(ocv);
+
+            Log_OC.d("share", "sharing for version " + ocv.toString());
+
+            if (ocv.compareTo(new OwnCloudVersion(0x040000)) >= 0) {
+                String APPS_PATH = "/apps/files_sharing/";
+                String SHARE_PATH = "ajax/share.php";
+
+                String SHARED_PATH = "/apps/files_sharing/get.php?token=";
+                
+                final String WEBDAV_SCRIPT = "webdav.php";
+                final String WEBDAV_FILES_LOCATION = "/files/";
+                
+                WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(account, getActivity().getApplicationContext());
+                HttpConnectionManagerParams params = new HttpConnectionManagerParams();
+                params.setMaxConnectionsPerHost(wc.getHostConfiguration(), 5);
+
+                //wc.getParams().setParameter("http.protocol.single-cookie-header", true);
+                //wc.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY);
+
+                PostMethod post = new PostMethod(am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + APPS_PATH + SHARE_PATH);
+
+                post.addRequestHeader("Content-type","application/x-www-form-urlencoded; charset=UTF-8" );
+                post.addRequestHeader("Referer", am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL));
+                List<NameValuePair> formparams = new ArrayList<NameValuePair>();
+                Log_OC.d("share", mPath+"");
+                formparams.add(new BasicNameValuePair("sources",mPath));
+                formparams.add(new BasicNameValuePair("uid_shared_with", "public"));
+                formparams.add(new BasicNameValuePair("permissions", "0"));
+                post.setRequestEntity(new StringRequestEntity(URLEncodedUtils.format(formparams, HTTP.UTF_8)));
+
+                int status;
+                try {
+                    PropFindMethod find = new PropFindMethod(url+"/");
+                    find.addRequestHeader("Referer", am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL));
+                    Log_OC.d("sharer", ""+ url+"/");
+                    
+                    for (org.apache.commons.httpclient.Header a : find.getRequestHeaders()) {
+                        Log_OC.d("sharer-h", a.getName() + ":"+a.getValue());
+                    }
+                    
+                    int status2 = wc.executeMethod(find);
+
+                    Log_OC.d("sharer", "propstatus "+status2);
+                    
+                    GetMethod get = new GetMethod(am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + "/");
+                    get.addRequestHeader("Referer", am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL));
+                    
+                    status2 = wc.executeMethod(get);
+
+                    Log_OC.d("sharer", "getstatus "+status2);
+                    Log_OC.d("sharer", "" + get.getResponseBodyAsString());
+                    
+                    for (org.apache.commons.httpclient.Header a : get.getResponseHeaders()) {
+                        Log_OC.d("sharer", a.getName() + ":"+a.getValue());
+                    }
+
+                    status = wc.executeMethod(post);
+                    for (org.apache.commons.httpclient.Header a : post.getRequestHeaders()) {
+                        Log_OC.d("sharer-h", a.getName() + ":"+a.getValue());
+                    }
+                    for (org.apache.commons.httpclient.Header a : post.getResponseHeaders()) {
+                        Log_OC.d("sharer", a.getName() + ":"+a.getValue());
+                    }
+                    String resp = post.getResponseBodyAsString();
+                    Log_OC.d("share", ""+post.getURI().toString());
+                    Log_OC.d("share", "returned status " + status);
+                    Log_OC.d("share", " " +resp);
+                    
+                    if(status != HttpStatus.SC_OK ||resp == null || resp.equals("") || resp.startsWith("false")) {
+                        return;
+                     }
+
+                    JSONObject jsonObject = new JSONObject (resp);
+                    String jsonStatus = jsonObject.getString("status");
+                    if(!jsonStatus.equals("success")) throw new Exception("Error while sharing file status != success");
+                    
+                    String token = jsonObject.getString("data");
+                    String uri = am.getUserData(account, AccountAuthenticator.KEY_OC_BASE_URL) + SHARED_PATH + token; 
+                    Log_OC.d("Actions:shareFile ok", "url: " + uri);   
+                    
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+                
+            } else if (ocv.compareTo(new OwnCloudVersion(0x030000)) >= 0) {
+                
+            }
+        }
+    }
+    */
+    
+}
index fecf26c..4e6affa 100644 (file)
@@ -25,7 +25,6 @@ import com.owncloud.android.ui.adapter.LocalFileListAdapter;
 import android.app.Activity;
 import android.os.Bundle;
 import android.os.Environment;
-import android.util.Log;
 import android.util.SparseBooleanArray;
 import android.view.LayoutInflater;
 import android.view.View;
index dac32c8..f872803 100644 (file)
@@ -28,7 +28,6 @@ import com.owncloud.android.datamodel.DataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
 import com.owncloud.android.files.services.FileUploader.FileUploaderBinder;
-import com.owncloud.android.network.OwnCloudClientUtils;
 import com.owncloud.android.operations.OnRemoteOperationListener;
 import com.owncloud.android.operations.RemoteOperation;
 import com.owncloud.android.operations.RemoveFileOperation;
@@ -42,7 +41,6 @@ import com.owncloud.android.ui.dialog.EditNameDialog;
 import com.owncloud.android.ui.dialog.EditNameDialog.EditNameDialogListener;
 import com.owncloud.android.ui.fragment.ConfirmationDialogFragment.ConfirmationDialogFragmentListener;
 
-import eu.alefzero.webdav.WebdavClient;
 import eu.alefzero.webdav.WebdavUtils;
 
 import android.accounts.Account;
@@ -52,7 +50,6 @@ import android.content.Intent;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
-import android.util.Log;
 import android.view.ContextMenu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
@@ -317,8 +314,7 @@ public class OCFileListFragment extends FragmentListView implements EditNameDial
             case R.id.action_download_file: {
                 Account account = AccountUtils.getCurrentOwnCloudAccount(getSherlockActivity());
                 RemoteOperation operation = new SynchronizeFileOperation(mTargetFile, null, mContainerActivity.getStorageManager(), account, true, false, getSherlockActivity());
-                WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(account, getSherlockActivity().getApplicationContext());
-                operation.execute(wc, mContainerActivity, mHandler);
+                operation.execute(account, getSherlockActivity(), mContainerActivity, mHandler, getSherlockActivity());
                 getSherlockActivity().showDialog(FileDisplayActivity.DIALOG_SHORT_WAIT);
                 return true;
             }
@@ -484,8 +480,7 @@ public class OCFileListFragment extends FragmentListView implements EditNameDial
                                                                 AccountUtils.getCurrentOwnCloudAccount(getActivity()), 
                                                                 newFilename, 
                                                                 mContainerActivity.getStorageManager());
-            WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(AccountUtils.getCurrentOwnCloudAccount(getSherlockActivity()), getSherlockActivity().getApplicationContext());
-            operation.execute(wc, mContainerActivity, mHandler);
+            operation.execute(AccountUtils.getCurrentOwnCloudAccount(getSherlockActivity()), getSherlockActivity(), mContainerActivity, mHandler, getSherlockActivity());
             getActivity().showDialog(FileDisplayActivity.DIALOG_SHORT_WAIT);
         }
     }
@@ -498,8 +493,7 @@ public class OCFileListFragment extends FragmentListView implements EditNameDial
                 RemoteOperation operation = new RemoveFileOperation( mTargetFile, 
                                                                     true, 
                                                                     mContainerActivity.getStorageManager());
-                WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(AccountUtils.getCurrentOwnCloudAccount(getSherlockActivity()), getSherlockActivity().getApplicationContext());
-                operation.execute(wc, mContainerActivity, mHandler);
+                operation.execute(AccountUtils.getCurrentOwnCloudAccount(getSherlockActivity()), getSherlockActivity(), mContainerActivity, mHandler, getSherlockActivity());
                 
                 getActivity().showDialog(FileDisplayActivity.DIALOG_SHORT_WAIT);
             }
index b11d341..773350a 100644 (file)
@@ -3,8 +3,8 @@
  *   Copyright (C) 2012-2013  ownCloud Inc.
  *
  *   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.
+ *   it under the terms of the GNU General Public License version 2,
+ *   as published by the Free Software Foundation.
  *
  *   This program is distributed in the hope that it will be useful,
  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -23,7 +23,6 @@ import android.accounts.Account;
 import android.app.Activity;
 import android.os.Bundle;
 import android.support.v4.app.FragmentStatePagerAdapter;
-import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.OnClickListener;
@@ -38,6 +37,7 @@ import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder;
 import com.owncloud.android.ui.fragment.FileFragment;
 
+import com.owncloud.android.Log_OC;
 import com.owncloud.android.R;
 
 import eu.alefzero.webdav.OnDatatransferProgressListener;
@@ -239,7 +239,7 @@ public class FileDownloadFragment extends SherlockFragment implements OnClickLis
                 break;
             }
             default:
-                Log.e(TAG, "Incorrect view clicked!");
+                Log_OC.e(TAG, "Incorrect view clicked!");
         }
     }
 
index be06c59..9b3e7d8 100644 (file)
@@ -16,8 +16,6 @@
  */
 package com.owncloud.android.ui.preview;
 
-import org.apache.commons.httpclient.methods.PostMethod;
-
 import android.accounts.Account;
 import android.app.Dialog;
 import android.app.ProgressDialog;
@@ -29,9 +27,7 @@ import android.content.IntentFilter;
 import android.content.ServiceConnection;
 import android.os.Bundle;
 import android.os.IBinder;
-import android.support.v4.app.Fragment;
 import android.support.v4.view.ViewPager;
-import android.util.Log;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.View.OnTouchListener;
@@ -52,6 +48,7 @@ import com.owncloud.android.ui.fragment.FileDetailFragment;
 import com.owncloud.android.ui.fragment.FileFragment;
 
 import com.owncloud.android.AccountUtils;
+import com.owncloud.android.Log_OC;
 import com.owncloud.android.R;
 
 /**
@@ -170,12 +167,12 @@ public class PreviewImageActivity extends SherlockFragmentActivity implements Fi
                 mDownloaderBinder = (FileDownloaderBinder) service;
                 if (mRequestWaitingForBinder) {
                     mRequestWaitingForBinder = false;
-                    Log.d(TAG, "Simulating reselection of current page after connection of download binder");
+                    Log_OC.d(TAG, "Simulating reselection of current page after connection of download binder");
                     onPageSelected(mViewPager.getCurrentItem());
                 }
                     
             } else if (component.equals(new ComponentName(PreviewImageActivity.this, FileUploader.class))) {
-                Log.d(TAG, "Upload service connected");
+                Log_OC.d(TAG, "Upload service connected");
                 mUploaderBinder = (FileUploaderBinder) service;
             } else {
                 return;
@@ -186,10 +183,10 @@ public class PreviewImageActivity extends SherlockFragmentActivity implements Fi
         @Override
         public void onServiceDisconnected(ComponentName component) {
             if (component.equals(new ComponentName(PreviewImageActivity.this, FileDownloader.class))) {
-                Log.d(TAG, "Download service suddenly disconnected");
+                Log_OC.d(TAG, "Download service suddenly disconnected");
                 mDownloaderBinder = null;
             } else if (component.equals(new ComponentName(PreviewImageActivity.this, FileUploader.class))) {
-                Log.d(TAG, "Upload service suddenly disconnected");
+                Log_OC.d(TAG, "Upload service suddenly disconnected");
                 mUploaderBinder = null;
             }
         }
@@ -328,7 +325,7 @@ public class PreviewImageActivity extends SherlockFragmentActivity implements Fi
     
     private void requestForDownload(OCFile file) {
         if (mDownloaderBinder == null) {
-            Log.d(TAG, "requestForDownload called without binder to download service");
+            Log_OC.d(TAG, "requestForDownload called without binder to download service");
             
         } else if (!mDownloaderBinder.isDownloading(mAccount, file)) {
             Intent i = new Intent(this, FileDownloader.class);
@@ -413,7 +410,7 @@ public class PreviewImageActivity extends SherlockFragmentActivity implements Fi
                     mPreviewImagePagerAdapter.notifyDataSetChanged();   // will trigger the creation of new fragments
                     
                 } else {
-                    Log.d(TAG, "Download finished, but the fragment is offscreen");
+                    Log_OC.d(TAG, "Download finished, but the fragment is offscreen");
                 }
                 
             }
index 2f51a63..8df06bf 100644 (file)
@@ -36,7 +36,6 @@ import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.Handler;
 import android.support.v4.app.FragmentStatePagerAdapter;
-import android.util.Log;
 import android.view.Display;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -54,7 +53,6 @@ import com.actionbarsherlock.view.MenuInflater;
 import com.actionbarsherlock.view.MenuItem;
 import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
-import com.owncloud.android.network.OwnCloudClientUtils;
 import com.owncloud.android.operations.OnRemoteOperationListener;
 import com.owncloud.android.operations.RemoteOperation;
 import com.owncloud.android.operations.RemoteOperationResult;
@@ -62,8 +60,8 @@ import com.owncloud.android.operations.RemoveFileOperation;
 import com.owncloud.android.ui.fragment.ConfirmationDialogFragment;
 import com.owncloud.android.ui.fragment.FileFragment;
 
+import com.owncloud.android.Log_OC;
 import com.owncloud.android.R;
-import eu.alefzero.webdav.WebdavClient;
 import eu.alefzero.webdav.WebdavUtils;
 
 
@@ -339,7 +337,7 @@ public class PreviewImageFragment extends SherlockFragment implements   FileFrag
             startActivity(i);
             
         } catch (Throwable t) {
-            Log.e(TAG, "Fail when trying to open with the mimeType provided from the ownCloud server: " + mFile.getMimetype());
+            Log_OC.e(TAG, "Fail when trying to open with the mimeType provided from the ownCloud server: " + mFile.getMimetype());
             boolean toastIt = true; 
             String mimeType = "";
             try {
@@ -358,13 +356,13 @@ public class PreviewImageFragment extends SherlockFragment implements   FileFrag
                 }
                 
             } catch (IndexOutOfBoundsException e) {
-                Log.e(TAG, "Trying to find out MIME type of a file without extension: " + storagePath);
+                Log_OC.e(TAG, "Trying to find out MIME type of a file without extension: " + storagePath);
                 
             } catch (ActivityNotFoundException e) {
-                Log.e(TAG, "No activity found to handle: " + storagePath + " with MIME type " + mimeType + " obtained from extension");
+                Log_OC.e(TAG, "No activity found to handle: " + storagePath + " with MIME type " + mimeType + " obtained from extension");
                 
             } catch (Throwable th) {
-                Log.e(TAG, "Unexpected problem when opening: " + storagePath, th);
+                Log_OC.e(TAG, "Unexpected problem when opening: " + storagePath, th);
                 
             } finally {
                 if (toastIt) {
@@ -404,8 +402,7 @@ public class PreviewImageFragment extends SherlockFragment implements   FileFrag
             mLastRemoteOperation = new RemoveFileOperation( mFile,      // TODO we need to review the interface with RemoteOperations, and use OCFile IDs instead of OCFile objects as parameters
                                                             true, 
                                                             mStorageManager);
-            WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getSherlockActivity().getApplicationContext());
-            mLastRemoteOperation.execute(wc, this, mHandler);
+            mLastRemoteOperation.execute(mAccount, getSherlockActivity(), this, mHandler, getSherlockActivity());
             
             getActivity().showDialog(PreviewImageActivity.DIALOG_SHORT_WAIT);
         }
@@ -557,24 +554,24 @@ public class PreviewImageFragment extends SherlockFragment implements   FileFrag
                 // really load the bitmap
                 options.inJustDecodeBounds = false; // the next decodeFile call will be real
                 result = BitmapFactory.decodeFile(storagePath, options);
-                //Log.d(TAG, "Image loaded - width: " + options.outWidth + ", loaded height: " + options.outHeight);
+                //Log_OC.d(TAG, "Image loaded - width: " + options.outWidth + ", loaded height: " + options.outHeight);
 
                 if (result == null) {
                     mErrorMessageId = R.string.preview_image_error_unknown_format;
-                    Log.e(TAG, "File could not be loaded as a bitmap: " + storagePath);
+                    Log_OC.e(TAG, "File could not be loaded as a bitmap: " + storagePath);
                 }
                 
             } catch (OutOfMemoryError e) {
                 mErrorMessageId = R.string.preview_image_error_unknown_format;
-                Log.e(TAG, "Out of memory occured for file " + storagePath, e);
+                Log_OC.e(TAG, "Out of memory occured for file " + storagePath, e);
                     
             } catch (NoSuchFieldError e) {
                 mErrorMessageId = R.string.common_error_unknown;
-                Log.e(TAG, "Error from access to unexisting field despite protection; file " + storagePath, e);
+                Log_OC.e(TAG, "Error from access to unexisting field despite protection; file " + storagePath, e);
                     
             } catch (Throwable t) {
                 mErrorMessageId = R.string.common_error_unknown;
-                Log.e(TAG, "Unexpected error loading " + mFile.getStoragePath(), t);
+                Log_OC.e(TAG, "Unexpected error loading " + mFile.getStoragePath(), t);
                 
             }
             return result;
index b5945bd..a253624 100644 (file)
@@ -16,7 +16,6 @@
  */
 package com.owncloud.android.ui.preview;
 
-import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
@@ -24,16 +23,9 @@ import java.util.Set;
 import java.util.Vector;
 
 import android.accounts.Account;
-import android.os.Bundle;
-import android.os.Parcelable;
 import android.support.v4.app.Fragment;
 import android.support.v4.app.FragmentManager;
 import android.support.v4.app.FragmentStatePagerAdapter;
-import android.support.v4.app.FragmentTransaction;
-import android.support.v4.view.PagerAdapter;
-import android.support.v4.view.ViewPager;
-import android.util.Log;
-import android.view.View;
 import android.view.ViewGroup;
 
 import com.owncloud.android.datamodel.DataStorageManager;
index 6fbf7d6..c26d8c7 100644 (file)
@@ -39,7 +39,6 @@ import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
 import android.support.v4.app.FragmentTransaction;
-import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
@@ -59,7 +58,6 @@ import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.media.MediaControlView;
 import com.owncloud.android.media.MediaService;
 import com.owncloud.android.media.MediaServiceBinder;
-import com.owncloud.android.network.OwnCloudClientUtils;
 import com.owncloud.android.operations.OnRemoteOperationListener;
 import com.owncloud.android.operations.RemoteOperation;
 import com.owncloud.android.operations.RemoteOperationResult;
@@ -70,8 +68,8 @@ import com.owncloud.android.ui.fragment.ConfirmationDialogFragment;
 import com.owncloud.android.ui.fragment.FileDetailFragment;
 import com.owncloud.android.ui.fragment.FileFragment;
 
+import com.owncloud.android.Log_OC;
 import com.owncloud.android.R;
-import eu.alefzero.webdav.WebdavClient;
 import eu.alefzero.webdav.WebdavUtils;
 
 /**
@@ -354,7 +352,7 @@ public class PreviewMediaFragment extends SherlockFragment implements
          */
         @Override
         public void onPrepared(MediaPlayer vp) {
-            Log.e(TAG, "onPrepared");
+            Log_OC.e(TAG, "onPrepared");
             mVideoPreview.seekTo(mSavedPlaybackPosition);
             if (mAutoplay) { 
                 mVideoPreview.start();
@@ -373,7 +371,7 @@ public class PreviewMediaFragment extends SherlockFragment implements
          */
         @Override
         public void onCompletion(MediaPlayer  mp) {
-            Log.e(TAG, "completed");
+            Log_OC.e(TAG, "completed");
             if (mp != null) {
                 mVideoPreview.seekTo(0);
                 // next lines are necessary to work around undesired video loops
@@ -428,7 +426,7 @@ public class PreviewMediaFragment extends SherlockFragment implements
         super.onStop();
         
         if (mMediaServiceConnection != null) {
-            Log.d(TAG, "Unbinding from MediaService ...");
+            Log_OC.d(TAG, "Unbinding from MediaService ...");
             if (mMediaServiceBinder != null && mMediaController != null) {
                 mMediaServiceBinder.unregisterMediaController(mMediaController);
             }
@@ -471,7 +469,7 @@ public class PreviewMediaFragment extends SherlockFragment implements
 
     private void playAudio() {
         if (!mMediaServiceBinder.isPlaying(mFile)) {
-            Log.d(TAG, "starting playback of " + mFile.getStoragePath());
+            Log_OC.d(TAG, "starting playback of " + mFile.getStoragePath());
             mMediaServiceBinder.start(mAccount, mFile, mAutoplay, mSavedPlaybackPosition);
             
         } else {
@@ -484,7 +482,7 @@ public class PreviewMediaFragment extends SherlockFragment implements
 
 
     private void bindMediaService() {
-        Log.d(TAG, "Binding to MediaService...");
+        Log_OC.d(TAG, "Binding to MediaService...");
         if (mMediaServiceConnection == null) {
             mMediaServiceConnection = new MediaServiceConnection();
         }
@@ -501,16 +499,16 @@ public class PreviewMediaFragment extends SherlockFragment implements
         @Override
         public void onServiceConnected(ComponentName component, IBinder service) {
             if (component.equals(new ComponentName(getActivity(), MediaService.class))) {
-                Log.d(TAG, "Media service connected");
+                Log_OC.d(TAG, "Media service connected");
                 mMediaServiceBinder = (MediaServiceBinder) service;
                 if (mMediaServiceBinder != null) {
                     prepareMediaController();
                     playAudio();    // do not wait for the touch of nobody to play audio
                     
-                    Log.d(TAG, "Successfully bound to MediaService, MediaController ready");
+                    Log_OC.d(TAG, "Successfully bound to MediaService, MediaController ready");
                     
                 } else {
-                    Log.e(TAG, "Unexpected response from MediaService while binding");
+                    Log_OC.e(TAG, "Unexpected response from MediaService while binding");
                 }
             }
         }
@@ -527,7 +525,7 @@ public class PreviewMediaFragment extends SherlockFragment implements
         @Override
         public void onServiceDisconnected(ComponentName component) {
             if (component.equals(new ComponentName(getActivity(), MediaService.class))) {
-                Log.e(TAG, "Media service suddenly disconnected");
+                Log_OC.e(TAG, "Media service suddenly disconnected");
                 if (mMediaController != null) {
                     mMediaController.setMediaPlayer(null);
                 } else {
@@ -559,7 +557,7 @@ public class PreviewMediaFragment extends SherlockFragment implements
             startActivity(i);
             
         } catch (Throwable t) {
-            Log.e(TAG, "Fail when trying to open with the mimeType provided from the ownCloud server: " + mFile.getMimetype());
+            Log_OC.e(TAG, "Fail when trying to open with the mimeType provided from the ownCloud server: " + mFile.getMimetype());
             boolean toastIt = true; 
             String mimeType = "";
             try {
@@ -578,13 +576,13 @@ public class PreviewMediaFragment extends SherlockFragment implements
                 }
                 
             } catch (IndexOutOfBoundsException e) {
-                Log.e(TAG, "Trying to find out MIME type of a file without extension: " + storagePath);
+                Log_OC.e(TAG, "Trying to find out MIME type of a file without extension: " + storagePath);
                 
             } catch (ActivityNotFoundException e) {
-                Log.e(TAG, "No activity found to handle: " + storagePath + " with MIME type " + mimeType + " obtained from extension");
+                Log_OC.e(TAG, "No activity found to handle: " + storagePath + " with MIME type " + mimeType + " obtained from extension");
                 
             } catch (Throwable th) {
-                Log.e(TAG, "Unexpected problem when opening: " + storagePath, th);
+                Log_OC.e(TAG, "Unexpected problem when opening: " + storagePath, th);
                 
             } finally {
                 if (toastIt) {
@@ -624,8 +622,7 @@ public class PreviewMediaFragment extends SherlockFragment implements
             mLastRemoteOperation = new RemoveFileOperation( mFile,      // TODO we need to review the interface with RemoteOperations, and use OCFile IDs instead of OCFile objects as parameters
                                                             true, 
                                                             mStorageManager);
-            WebdavClient wc = OwnCloudClientUtils.createOwnCloudClient(mAccount, getSherlockActivity().getApplicationContext());
-            mLastRemoteOperation.execute(wc, this, mHandler);
+            mLastRemoteOperation.execute(mAccount, getSherlockActivity(), this, mHandler, getSherlockActivity());
             
             boolean inDisplayActivity = getActivity() instanceof FileDisplayActivity;
             getActivity().showDialog((inDisplayActivity)? FileDisplayActivity.DIALOG_SHORT_WAIT : FileDetailActivity.DIALOG_SHORT_WAIT);
index c335bf4..3cbff7d 100644 (file)
@@ -28,12 +28,12 @@ import android.media.MediaPlayer.OnErrorListener;
 import android.media.MediaPlayer.OnPreparedListener;
 import android.net.Uri;
 import android.os.Bundle;
-import android.util.Log;
 import android.view.MotionEvent;
 import android.widget.MediaController;
 import android.widget.VideoView;
 
 import com.owncloud.android.AccountUtils;
+import com.owncloud.android.Log_OC;
 import com.owncloud.android.R;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.media.MediaService;
@@ -84,7 +84,7 @@ public class PreviewVideoActivity extends Activity implements OnCompletionListen
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        Log.e(TAG, "ACTIVITY\t\tonCreate");
+        Log_OC.e(TAG, "ACTIVITY\t\tonCreate");
         
         setContentView(R.layout.video_layout);
     
@@ -143,7 +143,7 @@ public class PreviewVideoActivity extends Activity implements OnCompletionListen
     @Override
     public void onSaveInstanceState(Bundle outState) {
         super.onSaveInstanceState(outState);
-        Log.e(TAG, "ACTIVITY\t\tonSaveInstanceState");
+        Log_OC.e(TAG, "ACTIVITY\t\tonSaveInstanceState");
         outState.putParcelable(PreviewVideoActivity.EXTRA_FILE, mFile);
         outState.putParcelable(PreviewVideoActivity.EXTRA_ACCOUNT, mAccount);
         outState.putInt(PreviewVideoActivity.EXTRA_START_POSITION, mVideoPlayer.getCurrentPosition());
@@ -153,7 +153,7 @@ public class PreviewVideoActivity extends Activity implements OnCompletionListen
     
     @Override
     public void onBackPressed() {
-        Log.e(TAG, "ACTIVTIY\t\tonBackPressed");
+        Log_OC.e(TAG, "ACTIVTIY\t\tonBackPressed");
         Intent i = new Intent();
         i.putExtra(EXTRA_AUTOPLAY, mVideoPlayer.isPlaying());
         i.putExtra(EXTRA_START_POSITION, mVideoPlayer.getCurrentPosition());
@@ -165,33 +165,33 @@ public class PreviewVideoActivity extends Activity implements OnCompletionListen
     @Override
     public void onResume() {
         super.onResume();
-        Log.e(TAG, "ACTIVTIY\t\tonResume");
+        Log_OC.e(TAG, "ACTIVTIY\t\tonResume");
     }
 
     
     @Override
     public void onStart() {
         super.onStart();
-        Log.e(TAG, "ACTIVTIY\t\tonStart");
+        Log_OC.e(TAG, "ACTIVTIY\t\tonStart");
     }
     
     @Override
     public void onDestroy() {
         super.onDestroy();
-        Log.e(TAG, "ACTIVITY\t\tonDestroy");
+        Log_OC.e(TAG, "ACTIVITY\t\tonDestroy");
     }
     
     @Override
     public void onStop() {
         super.onStop();
-        Log.e(TAG, "ACTIVTIY\t\tonStop");
+        Log_OC.e(TAG, "ACTIVTIY\t\tonStop");
     }
     
     
     @Override
     public void onPause() {
         super.onPause();
-        Log.e(TAG, "ACTIVTIY\t\tonPause");
+        Log_OC.e(TAG, "ACTIVTIY\t\tonPause");
     }
     
     
@@ -204,7 +204,7 @@ public class PreviewVideoActivity extends Activity implements OnCompletionListen
      */
     @Override
     public void onPrepared(MediaPlayer mp) {
-        Log.e(TAG, "ACTIVITY\t\tonPrepare");
+        Log_OC.e(TAG, "ACTIVITY\t\tonPrepare");
         mVideoPlayer.seekTo(mSavedPlaybackPosition);
         if (mAutoplay) { 
             mVideoPlayer.start();
@@ -235,7 +235,7 @@ public class PreviewVideoActivity extends Activity implements OnCompletionListen
      */
     @Override
     public boolean onError(MediaPlayer mp, int what, int extra) {
-        Log.e(TAG, "Error in video playback, what = " + what + ", extra = " + extra);
+        Log_OC.e(TAG, "Error in video playback, what = " + what + ", extra = " + extra);
         
         if (mMediaController != null) {
             mMediaController.hide();
index 1c7acaf..dda7b5a 100644 (file)
@@ -24,7 +24,6 @@ import android.content.Context;
 import android.net.Uri;
 import android.os.Environment;
 import android.os.StatFs;
-import android.util.Log;
 
 import com.owncloud.android.R;
 import com.owncloud.android.datamodel.OCFile;
index 9830f66..fdabebe 100644 (file)
@@ -15,6 +15,7 @@
  *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  *
  */
+
 package eu.alefzero.webdav;
 
 import java.io.BufferedInputStream;
@@ -22,14 +23,20 @@ import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
 
 import org.apache.commons.httpclient.Credentials;
+import org.apache.commons.httpclient.HostConfiguration;
 import org.apache.commons.httpclient.HttpClient;
 import org.apache.commons.httpclient.HttpConnectionManager;
 import org.apache.commons.httpclient.HttpException;
+import org.apache.commons.httpclient.HttpMethod;
 import org.apache.commons.httpclient.HttpMethodBase;
+import org.apache.commons.httpclient.HttpState;
 import org.apache.commons.httpclient.HttpVersion;
 import org.apache.commons.httpclient.UsernamePasswordCredentials;
+import org.apache.commons.httpclient.auth.AuthPolicy;
 import org.apache.commons.httpclient.auth.AuthScope;
 import org.apache.commons.httpclient.methods.GetMethod;
 import org.apache.commons.httpclient.methods.HeadMethod;
@@ -39,12 +46,13 @@ import org.apache.http.HttpStatus;
 import org.apache.http.params.CoreProtocolPNames;
 import org.apache.jackrabbit.webdav.client.methods.DavMethod;
 import org.apache.jackrabbit.webdav.client.methods.DeleteMethod;
-import org.apache.jackrabbit.webdav.client.methods.MkColMethod;
 
 import com.owncloud.android.Log_OC;
 
+import com.owncloud.android.network.BearerAuthScheme;
+import com.owncloud.android.network.BearerCredentials;
+
 import android.net.Uri;
-import android.util.Log;
 
 public class WebdavClient extends HttpClient {
     private Uri mUri;
@@ -65,176 +73,32 @@ public class WebdavClient extends HttpClient {
         getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
     }
 
-    public void setCredentials(String username, String password) {
-        getParams().setAuthenticationPreemptive(true);
-        getState().setCredentials(AuthScope.ANY,
-                getCredentials(username, password));
-    }
-
-    private Credentials getCredentials(String username, String password) {
-        if (mCredentials == null)
-            mCredentials = new UsernamePasswordCredentials(username, password);
-        return mCredentials;
-    }
-    
-    /**
-     * Downloads a file in remoteFilepath to the local targetPath.
-     * 
-     * @param remoteFilepath    Path to the file in the remote server, URL DECODED. 
-     * @param targetFile        Local path to save the downloaded file.
-     * @return                  'True' when the file is successfully downloaded.
-     */
-    public boolean downloadFile(String remoteFilePath, File targetFile) {
-        boolean ret = false;
-        GetMethod get = new GetMethod(mUri.toString() + WebdavUtils.encodePath(remoteFilePath));
-
-        try {
-            int status = executeMethod(get);
-            if (status == HttpStatus.SC_OK) {
-                targetFile.createNewFile();
-                BufferedInputStream bis = new BufferedInputStream(
-                        get.getResponseBodyAsStream());
-                FileOutputStream fos = new FileOutputStream(targetFile);
-
-                byte[] bytes = new byte[4096];
-                int readResult;
-                while ((readResult = bis.read(bytes)) != -1) {
-                    if (mDataTransferListener != null)
-                        mDataTransferListener.onTransferProgress(readResult);
-                    fos.write(bytes, 0, readResult);
-                }
-                fos.close();
-                ret = true;
-            } else {
-                exhaustResponse(get.getResponseBodyAsStream());
-            }
-            Log_OC.e(TAG, "Download of " + remoteFilePath + " to " + targetFile + " finished with HTTP status " + status + (!ret?"(FAIL)":""));
-            
-        } catch (Exception e) {
-            logException(e, "dowloading " + remoteFilePath);
-            
-        } finally {
-            if (!ret && targetFile.exists()) {
-                targetFile.delete();
-            }
-            get.releaseConnection();    // let the connection available for other methods
-        }
-        return ret;
-    }
-    
-    /**
-     * Deletes a remote file via webdav
-     * @param remoteFilePath       Remote file path of the file to delete, in URL DECODED format.
-     * @return
-     */
-    public boolean deleteFile(String remoteFilePath) {
-        boolean ret = false;
-        DavMethod delete = new DeleteMethod(mUri.toString() + WebdavUtils.encodePath(remoteFilePath));
-        try {
-            int status = executeMethod(delete);
-            ret = (status == HttpStatus.SC_OK || status == HttpStatus.SC_ACCEPTED || status == HttpStatus.SC_NO_CONTENT);
-            exhaustResponse(delete.getResponseBodyAsStream());
-            
-            Log_OC.e(TAG, "DELETE of " + remoteFilePath + " finished with HTTP status " + status +  (!ret?"(FAIL)":""));
-            
-        } catch (Exception e) {
-            logException(e, "deleting " + remoteFilePath);
-            
-        } finally {
-            delete.releaseConnection();    // let the connection available for other methods
-        }
-        return ret;
-    }
-
-    
-    public void setDataTransferProgressListener(OnDatatransferProgressListener listener) {
-        mDataTransferListener = listener;
-    }
-    
-    /**
-     * Creates or update a file in the remote server with the contents of a local file.
-     * 
-     * @param localFile         Path to the local file to upload.
-     * @param remoteTarget      Remote path to the file to create or update, URL DECODED
-     * @param contentType       MIME type of the file.
-     * @return                  Status HTTP code returned by the server.
-     * @throws IOException      When a transport error that could not be recovered occurred while uploading the file to the server.
-     * @throws HttpException    When a violation of the HTTP protocol occurred. 
-     */
-    public int putFile(String localFile, String remoteTarget, String contentType) throws HttpException, IOException {
-        int status = -1;
-        PutMethod put = new PutMethod(mUri.toString() + WebdavUtils.encodePath(remoteTarget));
+    public void setBearerCredentials(String accessToken) {
+        AuthPolicy.registerAuthScheme(BearerAuthScheme.AUTH_POLICY, BearerAuthScheme.class);
         
-        try {
-            File f = new File(localFile);
-            FileRequestEntity entity = new FileRequestEntity(f, contentType);
-            entity.addDatatransferProgressListener(mDataTransferListener);
-            put.setRequestEntity(entity);
-            status = executeMethod(put);
-            
-            exhaustResponse(put.getResponseBodyAsStream());
-            
-        } finally {
-            put.releaseConnection();    // let the connection available for other methods
-        }
-        return status;
-    }
-    
-    /**
-     * Tries to log in to the current URI, with the current credentials
-     * 
-     * @return A {@link HttpStatus}-Code of the result. SC_OK is good.
-     */
-    public int tryToLogin() {
-        int status = 0;
-        HeadMethod head = new HeadMethod(mUri.toString());
-        try {
-            status = executeMethod(head);
-            boolean result = status == HttpStatus.SC_OK;
-            Log_OC.d(TAG, "HEAD for " + mUri + " finished with HTTP status " + status + (!result?"(FAIL)":""));
-            exhaustResponse(head.getResponseBodyAsStream());
-            
-        } catch (Exception e) {
-            logException(e, "trying to login at " + mUri.toString());
-            
-        } finally {
-            head.releaseConnection();
-        }
-        return status;
+        List<String> authPrefs = new ArrayList<String>(1);
+        authPrefs.add(BearerAuthScheme.AUTH_POLICY);
+        getParams().setParameter(AuthPolicy.AUTH_SCHEME_PRIORITY, authPrefs);        
+        
+        mCredentials = new BearerCredentials(accessToken);
+        getState().setCredentials(AuthScope.ANY, mCredentials);
     }
 
-    /**
-     * Creates a remote directory with the received path.
-     * 
-     * @param path      Path of the directory to create, URL DECODED
-     * @return          'True' when the directory is successfully created
-     */
-    public boolean createDirectory(String path) {
-        boolean result = false;
-        int status = -1;
-        MkColMethod mkcol = new MkColMethod(mUri.toString() + WebdavUtils.encodePath(path));
-        try {
-            Log_OC.d(TAG, "Creating directory " + path);
-            status = executeMethod(mkcol);
-            Log_OC.d(TAG, "Status returned: " + status);
-            result = mkcol.succeeded();
-            
-            Log_OC.d(TAG, "MKCOL to " + path + " finished with HTTP status " + status + (!result?"(FAIL)":""));
-            exhaustResponse(mkcol.getResponseBodyAsStream());
-            
-        } catch (Exception e) {
-            logException(e, "creating directory " + path);
-            
-        } finally {
-            mkcol.releaseConnection();    // let the connection available for other methods
-        }
-        return result;
+    public void setBasicCredentials(String username, String password) {
+        List<String> authPrefs = new ArrayList<String>(1);
+        authPrefs.add(AuthPolicy.BASIC);
+        getParams().setParameter(AuthPolicy.AUTH_SCHEME_PRIORITY, authPrefs);        
+        
+        getParams().setAuthenticationPreemptive(true);
+        mCredentials = new UsernamePasswordCredentials(username, password);
+        getState().setCredentials(AuthScope.ANY, mCredentials);
     }
     
-    
     /**
      * Check if a file exists in the OC server
      * 
+     * TODO replace with ExistenceOperation
+     * 
      * @return              'true' if the file exists; 'false' it doesn't exist
      * @throws  Exception   When the existence could not be determined
      */
@@ -250,7 +114,7 @@ public class WebdavClient extends HttpClient {
             head.releaseConnection();    // let the connection available for other methods
         }
     }
-
+    
     /**
      * Requests the received method with the received timeout (milliseconds).
      * 
@@ -300,25 +164,6 @@ public class WebdavClient extends HttpClient {
     }
 
     /**
-     * Logs an exception triggered in a HTTP request. 
-     * 
-     * @param e         Caught exception.
-     * @param doing     Suffix to add at the end of the logged message.
-     */
-    private void logException(Exception e, String doing) {
-        if (e instanceof HttpException) {
-            Log_OC.e(TAG, "HTTP violation while " + doing, e);
-
-        } else if (e instanceof IOException) {
-            Log_OC.e(TAG, "Unrecovered transport exception while " + doing, e);
-
-        } else {
-            Log_OC.e(TAG, "Unexpected exception while " + doing, e);
-        }
-    }
-
-    
-    /**
      * Sets the connection and wait-for-data timeouts to be applied by default to the methods performed by this client.
      */
     public void setDefaultTimeouts(int defaultDataTimeout, int defaultConnectionTimeout) {
@@ -338,4 +183,8 @@ public class WebdavClient extends HttpClient {
         return mUri;
     }
 
+    public final Credentials getCredentials() {\r
+        return mCredentials;\r
+    }\r
+\r
 }
index 450ca6b..46923c6 100644 (file)
@@ -26,7 +26,6 @@ import org.apache.jackrabbit.webdav.property.DavPropertySet;
 import com.owncloud.android.Log_OC;
 
 import android.net.Uri;
-import android.util.Log;
 
 public class WebdavEntry {
     private String mName, mPath, mUri, mContentType;