Merge branch 'develop' into create_folder_during_upload_pr_701_with_develop
authormasensio <masensio@solidgear.es>
Mon, 16 Mar 2015 10:15:27 +0000 (11:15 +0100)
committermasensio <masensio@solidgear.es>
Mon, 16 Mar 2015 10:15:27 +0000 (11:15 +0100)
285 files changed:
AndroidManifest.xml
CHANGELOG.md [new file with mode: 0644]
gradle/wrapper/gradle-wrapper.properties
oc_jb_workaround/AndroidManifest.xml
oc_jb_workaround/res/values/setup.xml
oc_jb_workaround/src/com/owncloud/android/workaround/accounts/AccountAuthenticatorService.java
owncloud-android-library
res/anim/disappear.xml
res/anim/grow_from_bottom.xml
res/anim/grow_from_bottomleft_to_topright.xml
res/anim/grow_from_bottomright_to_topleft.xml
res/anim/grow_from_top.xml
res/anim/grow_from_topleft_to_bottomright.xml
res/anim/grow_from_topright_to_bottomleft.xml
res/anim/pump_bottom.xml
res/anim/pump_top.xml
res/anim/shrink_from_bottom.xml
res/anim/shrink_from_bottomleft_to_topright.xml
res/anim/shrink_from_bottomright_to_topleft.xml
res/anim/shrink_from_top.xml
res/anim/shrink_from_topleft_to_bottomright.xml
res/anim/shrink_from_topright_to_bottomleft.xml
res/drawable-hdpi/copy_link.png
res/drawable-hdpi/ic_favorite.png
res/drawable-hdpi/shared_with_me.png
res/drawable-hdpi/sharedlink.png
res/drawable-ldpi/copy_link.png
res/drawable-mdpi/copy_link.png
res/drawable-mdpi/ic_favorite.png
res/drawable-mdpi/shared_with_me.png
res/drawable-mdpi/sharedlink.png
res/drawable-xhdpi/copy_link.png
res/drawable-xhdpi/file.png [new file with mode: 0644]
res/drawable-xhdpi/file_doc.png [new file with mode: 0644]
res/drawable-xhdpi/file_image.png [new file with mode: 0644]
res/drawable-xhdpi/file_movie.png [new file with mode: 0644]
res/drawable-xhdpi/file_pdf.png [new file with mode: 0644]
res/drawable-xhdpi/file_ppt.png [new file with mode: 0644]
res/drawable-xhdpi/file_sound.png [new file with mode: 0644]
res/drawable-xhdpi/file_xls.png [new file with mode: 0644]
res/drawable-xhdpi/file_zip.png [new file with mode: 0644]
res/drawable-xhdpi/folder_public.png [new file with mode: 0644]
res/drawable-xhdpi/ic_favorite.png
res/drawable-xhdpi/ic_menu_archive.png [new file with mode: 0644]
res/drawable-xhdpi/shared_with_me.png
res/drawable-xhdpi/shared_with_me_folder.png [new file with mode: 0644]
res/drawable-xhdpi/sharedlink.png
res/drawable/action_item_btn.xml
res/drawable/btn.xml
res/drawable/btn_round.xml
res/drawable/btn_round_pressed.xml
res/drawable/downloading_file_indicator.png
res/drawable/list_selector.xml
res/drawable/main_header_bg.xml
res/drawable/progress_small.xml
res/drawable/split_action_bg.xml
res/drawable/uploader_list_separator.xml
res/layout-land/account_setup.xml
res/layout-v11/activity_row.xml
res/layout-v11/notification_with_progress_bar.xml
res/layout-v14/generic_explanation.xml
res/layout/account_setup.xml
res/layout/action_item.xml
res/layout/activity_row.xml
res/layout/edit_box_dialog.xml
res/layout/file_details_empty.xml
res/layout/file_details_fragment.xml
res/layout/file_download_fragment.xml
res/layout/file_preview.xml
res/layout/files.xml
res/layout/files_folder_picker.xml
res/layout/generic_explanation.xml
res/layout/grid_image.xml [new file with mode: 0644]
res/layout/grid_item.xml [new file with mode: 0644]
res/layout/list_fragment.xml
res/layout/list_item.xml
res/layout/loading_dialog.xml
res/layout/log_item.xml
res/layout/log_send_file.xml
res/layout/media_control.xml
res/layout/notification_with_progress_bar.xml
res/layout/password_dialog.xml [new file with mode: 0644]
res/layout/pincodelock.xml
res/layout/popup.xml
res/layout/preview_image_activity.xml
res/layout/preview_image_fragment.xml
res/layout/ssl_untrusted_cert_layout.xml
res/layout/ssl_validator_layout.xml
res/layout/sso_dialog.xml
res/layout/upload_files_layout.xml
res/layout/uploader_layout.xml
res/layout/uploader_list_item_layout.xml
res/layout/video_layout.xml
res/menu/account_picker_long_click.xml
res/menu/file_actions_menu.xml
res/menu/main_menu.xml
res/raw-de/changelog.html
res/raw-es/changelog.html
res/raw/changelog.html
res/values-ar/strings.xml
res/values-az/strings.xml
res/values-bg-rBG/strings.xml
res/values-bn-rBD/strings.xml
res/values-ca/strings.xml
res/values-cs-rCZ/strings.xml
res/values-da/strings.xml
res/values-de-rDE/strings.xml
res/values-de/strings.xml
res/values-el/strings.xml
res/values-en-rGB/strings.xml
res/values-eo/strings.xml
res/values-es-rAR/strings.xml
res/values-es-rCR/strings.xml
res/values-es-rMX/strings.xml
res/values-es/strings.xml
res/values-et-rEE/strings.xml
res/values-eu/strings.xml
res/values-fa/strings.xml
res/values-fi-rFI/strings.xml
res/values-fr/strings.xml
res/values-gl/strings.xml
res/values-hu-rHU/strings.xml
res/values-id/strings.xml
res/values-it/strings.xml
res/values-ja-rJP/strings.xml
res/values-km/strings.xml
res/values-ko/strings.xml
res/values-large-land/bools.xml
res/values-lt-rLT/strings.xml
res/values-lv/strings.xml
res/values-mk/strings.xml
res/values-mr/strings.xml [new file with mode: 0644]
res/values-nb-rNO/strings.xml
res/values-nl/strings.xml
res/values-pl/strings.xml
res/values-pt-rBR/strings.xml
res/values-pt-rPT/strings.xml
res/values-ro/strings.xml
res/values-ru/strings.xml
res/values-sk-rSK/strings.xml
res/values-sl/strings.xml
res/values-sq/strings.xml
res/values-sr/strings.xml
res/values-sv/strings.xml
res/values-tr/strings.xml
res/values-ug/strings.xml
res/values-uk/strings.xml
res/values-zh-rCN/strings.xml
res/values-zh-rTW/strings.xml
res/values/bools.xml
res/values/colors.xml
res/values/dims.xml
res/values/strings.xml
res/values/styles.xml
res/xml/authenticator.xml
res/xml/preferences.xml
res/xml/syncadapter_files.xml
src/com/owncloud/android/MainApp.java
src/com/owncloud/android/authentication/AccountAuthenticator.java
src/com/owncloud/android/authentication/AccountAuthenticatorService.java
src/com/owncloud/android/authentication/AccountUtils.java
src/com/owncloud/android/authentication/AuthenticatorActivity.java
src/com/owncloud/android/authentication/AuthenticatorAsyncTask.java [new file with mode: 0644]
src/com/owncloud/android/authentication/OAuth2Constants.java
src/com/owncloud/android/authentication/SsoWebViewClient.java
src/com/owncloud/android/datamodel/FileDataStorageManager.java
src/com/owncloud/android/datamodel/OCFile.java
src/com/owncloud/android/datamodel/ThumbnailsCacheManager.java
src/com/owncloud/android/db/DbHandler.java
src/com/owncloud/android/db/ProviderMeta.java
src/com/owncloud/android/files/BootupBroadcastReceiver.java
src/com/owncloud/android/files/FileMenuFilter.java
src/com/owncloud/android/files/FileOperationsHelper.java
src/com/owncloud/android/files/InstantUploadBroadcastReceiver.java
src/com/owncloud/android/files/services/FileDownloader.java
src/com/owncloud/android/files/services/FileUploader.java
src/com/owncloud/android/files/services/IndexedForest.java
src/com/owncloud/android/files/services/OnUploadCompletedListener.java
src/com/owncloud/android/media/MediaControlView.java
src/com/owncloud/android/media/MediaService.java
src/com/owncloud/android/media/MediaServiceBinder.java
src/com/owncloud/android/notifications/NotificationBuilderWithProgressBar.java
src/com/owncloud/android/notifications/NotificationDelayer.java
src/com/owncloud/android/operations/CreateFolderOperation.java
src/com/owncloud/android/operations/CreateShareOperation.java
src/com/owncloud/android/operations/DetectAuthenticationMethodOperation.java
src/com/owncloud/android/operations/DownloadFileOperation.java
src/com/owncloud/android/operations/GetServerInfoOperation.java
src/com/owncloud/android/operations/GetSharesForFileOperation.java
src/com/owncloud/android/operations/GetSharesOperation.java
src/com/owncloud/android/operations/MoveFileOperation.java
src/com/owncloud/android/operations/OAuth2GetAccessToken.java
src/com/owncloud/android/operations/RefreshFolderOperation.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/UnshareLinkOperation.java
src/com/owncloud/android/operations/UpdateOCVersionOperation.java
src/com/owncloud/android/operations/UploadFileOperation.java
src/com/owncloud/android/operations/common/SyncOperation.java
src/com/owncloud/android/providers/FileContentProvider.java
src/com/owncloud/android/services/OperationsService.java
src/com/owncloud/android/services/SyncFolderHandler.java
src/com/owncloud/android/services/observer/FileObserverService.java
src/com/owncloud/android/services/observer/FolderObserver.java
src/com/owncloud/android/syncadapter/AbstractOwnCloudSyncAdapter.java
src/com/owncloud/android/syncadapter/ContactSyncAdapter.java
src/com/owncloud/android/syncadapter/ContactSyncService.java
src/com/owncloud/android/syncadapter/FileSyncAdapter.java
src/com/owncloud/android/syncadapter/FileSyncService.java
src/com/owncloud/android/ui/ActionItem.java
src/com/owncloud/android/ui/CheckBoxPreferenceWithLongTitle.java
src/com/owncloud/android/ui/CustomPopup.java
src/com/owncloud/android/ui/ExtendedListView.java
src/com/owncloud/android/ui/PreferenceWithLongSummary.java
src/com/owncloud/android/ui/QuickAction.java
src/com/owncloud/android/ui/RadioButtonPreference.java
src/com/owncloud/android/ui/SquareImageView.java [new file with mode: 0644]
src/com/owncloud/android/ui/SquareLinearLayout.java [new file with mode: 0644]
src/com/owncloud/android/ui/activity/ComponentsGetter.java
src/com/owncloud/android/ui/activity/ConflictsResolveActivity.java
src/com/owncloud/android/ui/activity/CopyToClipboardActivity.java
src/com/owncloud/android/ui/activity/ErrorsWhileCopyingHandlerActivity.java
src/com/owncloud/android/ui/activity/FileActivity.java
src/com/owncloud/android/ui/activity/FileDisplayActivity.java
src/com/owncloud/android/ui/activity/FolderPickerActivity.java
src/com/owncloud/android/ui/activity/GenericExplanationActivity.java
src/com/owncloud/android/ui/activity/HookActivity.java
src/com/owncloud/android/ui/activity/LogHistoryActivity.java
src/com/owncloud/android/ui/activity/OnEnforceableRefreshListener.java
src/com/owncloud/android/ui/activity/PinCodeActivity.java
src/com/owncloud/android/ui/activity/Preferences.java
src/com/owncloud/android/ui/activity/UploadFilesActivity.java
src/com/owncloud/android/ui/activity/UploadPathActivity.java
src/com/owncloud/android/ui/activity/Uploader.java
src/com/owncloud/android/ui/adapter/CertificateCombinedExceptionViewAdapter.java
src/com/owncloud/android/ui/adapter/DiskLruImageCache.java
src/com/owncloud/android/ui/adapter/FileListListAdapter.java
src/com/owncloud/android/ui/adapter/LocalFileListAdapter.java
src/com/owncloud/android/ui/adapter/LogListAdapter.java
src/com/owncloud/android/ui/adapter/SslCertificateViewAdapter.java
src/com/owncloud/android/ui/adapter/SslErrorViewAdapter.java
src/com/owncloud/android/ui/adapter/X509CertificateViewAdapter.java
src/com/owncloud/android/ui/dialog/ChangelogDialog.java
src/com/owncloud/android/ui/dialog/ConfirmationDialogFragment.java
src/com/owncloud/android/ui/dialog/ConflictsResolveDialog.java
src/com/owncloud/android/ui/dialog/CreateFolderDialogFragment.java
src/com/owncloud/android/ui/dialog/CredentialsDialogFragment.java
src/com/owncloud/android/ui/dialog/IndeterminateProgressDialog.java
src/com/owncloud/android/ui/dialog/LoadingDialog.java
src/com/owncloud/android/ui/dialog/RemoveFileDialogFragment.java
src/com/owncloud/android/ui/dialog/RenameFileDialogFragment.java
src/com/owncloud/android/ui/dialog/SamlWebViewDialog.java
src/com/owncloud/android/ui/dialog/ShareLinkToDialog.java
src/com/owncloud/android/ui/dialog/SharePasswordDialogFragment.java [new file with mode: 0644]
src/com/owncloud/android/ui/dialog/SslUntrustedCertDialog.java
src/com/owncloud/android/ui/dialog/SslValidatorDialog.java
src/com/owncloud/android/ui/dialog/SsoWebView.java
src/com/owncloud/android/ui/fragment/AuthenticatorAccountDetailsFragment.java
src/com/owncloud/android/ui/fragment/AuthenticatorGetStartedFragment.java
src/com/owncloud/android/ui/fragment/ExtendedListFragment.java
src/com/owncloud/android/ui/fragment/FileDetailFragment.java
src/com/owncloud/android/ui/fragment/FileFragment.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/BitmapUtils.java
src/com/owncloud/android/utils/DisplayUtils.java
src/com/owncloud/android/utils/ErrorMessageAdapter.java
src/com/owncloud/android/utils/FileStorageUtils.java
src/com/owncloud/android/utils/OwnCloudSession.java
src/com/owncloud/android/utils/RecursiveFileObserver.java
src/com/owncloud/android/utils/TouchImageViewCustom.java [deleted file]
src/com/owncloud/android/utils/UriUtils.java
src/com/owncloud/android/widgets/ActionEditText.java
src/third_parties/in/srain/cube/GridViewWithHeaderAndFooter.java [new file with mode: 0644]
src/third_parties/in/srain/cube/lapache-2.0.txt [new file with mode: 0644]
src/third_parties/michaelOrtiz/TouchImageViewCustom.java [new file with mode: 0644]
tests/src/com/owncloud/android/test/AccountUtilsTest.java

index fd92d3d..f0d1e9d 100644 (file)
@@ -3,7 +3,7 @@
   ownCloud Android client application
 
   Copyright (C) 2012  Bartek Przybylski
-  Copyright (C) 2012-2014 ownCloud Inc.
+  Copyright (C) 2012-2015 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,
@@ -18,8 +18,8 @@
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  -->
 <manifest package="com.owncloud.android"
-    android:versionCode="10600200"
-    android:versionName="1.6.2" xmlns:android="http://schemas.android.com/apk/res/android">
+    android:versionCode="10700000"
+    android:versionName="1.7.0" xmlns:android="http://schemas.android.com/apk/res/android">
 
     <uses-permission android:name="android.permission.GET_ACCOUNTS" />
     <uses-permission android:name="android.permission.USE_CREDENTIALS" />
@@ -86,9 +86,6 @@
             android:name=".ui.activity.Preferences"
             android:theme="@style/Theme.ownCloud" >
         </activity>
-        <activity android:name=".ui.activity.PreferencesNewSessionewSession" >
-        </activity>
-        
         <activity      
             android:name=".ui.preview.PreviewImageActivity" 
             />
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644 (file)
index 0000000..51d5242
--- /dev/null
@@ -0,0 +1,20 @@
+## 1.7.0 (19 February 2015)
+
+- Download full folders
+- Grid view for images
+- Remote thumbnails (OC Server 8.0+)
+- Added number of files and folders at the end of the list
+- "Open with" in contextual menu
+- Downloads added to Media Provider
+- Uploads:
+  + Local thumbnails in section "Files"
+  + Multiple selection in "Content from other apps" (Android 4.3+)
+- Gallery: 
+  + proper handling of EXIF
+  + obey sorting in the list of files
+- Settings view updated
+- Improved subjects in e-mails
+- Bugs fixed
+...
+
+
index ae8d5b2..5a1c438 100644 (file)
@@ -1,4 +1,4 @@
-#Mon Jan 19 09:42:11 CET 2015
+#Sun Jan 18 17:01:43 CET 2015
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
index 478e3c4..18ffb4c 100644 (file)
@@ -1,8 +1,8 @@
 <?xml version="1.0" encoding="utf-8"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.owncloud.android.workaround.accounts"
-    android:versionCode="0100020"
-    android:versionName="1.0.20" >
+    android:versionCode="0100021"
+    android:versionName="1.0.21" >
 
     <uses-sdk
         android:minSdkVersion="16"
index 0bf5e1d..d4d347e 100644 (file)
@@ -2,7 +2,7 @@
 <!--
   ownCloud Android client application
 
-  Copyright (C) 2012-2013 ownCloud Inc.
+  Copyright (C) 2015 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,
index 5a7c57e..6526f94 100644 (file)
@@ -1,5 +1,5 @@
 /* ownCloud Jelly Bean Workaround for lost credentials
- *   Copyright (C) 2013 ownCloud Inc.
+ *   Copyright (C) 2015 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,
index e87f5f2..0dd68c1 160000 (submodule)
@@ -1 +1 @@
-Subproject commit e87f5f25ad91950d47ec9b6fa01401360cd7ec8d
+Subproject commit 0dd68c1f65c31bd716b2de26e644c87c98e9b9c2
index 8bb865d..5fd6f07 100644 (file)
@@ -3,7 +3,7 @@
   ownCloud Android client application
 
   Copyright (C) 2012  Bartek Przybylski
-  Copyright (C) 2012-2013 ownCloud Inc.
+  Copyright (C) 2015 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,
index 78bd62b..774c8d8 100644 (file)
@@ -3,7 +3,7 @@
   ownCloud Android client application
 
   Copyright (C) 2012  Bartek Przybylski
-  Copyright (C) 2012-2013 ownCloud Inc.
+  Copyright (C) 2015 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,
index 32b251b..c7920d3 100644 (file)
@@ -3,7 +3,7 @@
   ownCloud Android client application
 
   Copyright (C) 2012  Bartek Przybylski
-  Copyright (C) 2012-2013 ownCloud Inc.
+  Copyright (C) 2015 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,
index f92b219..aff710a 100644 (file)
@@ -3,7 +3,7 @@
   ownCloud Android client application\r
 \r
   Copyright (C) 2012  Bartek Przybylski\r
-  Copyright (C) 2012-2013 ownCloud Inc.\r
+  Copyright (C) 2015 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
index 851f847..eec19be 100644 (file)
@@ -3,7 +3,7 @@
   ownCloud Android client application
 
   Copyright (C) 2012  Bartek Przybylski
-  Copyright (C) 2012-2013 ownCloud Inc.
+  Copyright (C) 2015 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,
index 951ca01..4054bcb 100644 (file)
@@ -3,7 +3,7 @@
   ownCloud Android client application
 
   Copyright (C) 2012  Bartek Przybylski
-  Copyright (C) 2012-2013 ownCloud Inc.
+  Copyright (C) 2015 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,
index 972a5b7..6e77a2f 100644 (file)
@@ -3,7 +3,7 @@
   ownCloud Android client application\r
 \r
   Copyright (C) 2012  Bartek Przybylski\r
-  Copyright (C) 2012-2013 ownCloud Inc.\r
+  Copyright (C) 2015 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
index 6016e00..800c583 100644 (file)
@@ -3,7 +3,7 @@
   ownCloud Android client application
 
   Copyright (C) 2012  Bartek Przybylski
-  Copyright (C) 2012-2013 ownCloud Inc.
+  Copyright (C) 2015 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,
index fa0b6c9..f27627d 100644 (file)
@@ -3,7 +3,7 @@
   ownCloud Android client application
 
   Copyright (C) 2012  Bartek Przybylski
-  Copyright (C) 2012-2013 ownCloud Inc.
+  Copyright (C) 2015 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,
index c330980..7de2c91 100644 (file)
@@ -3,7 +3,7 @@
   ownCloud Android client application
 
   Copyright (C) 2012  Bartek Przybylski
-  Copyright (C) 2012-2013 ownCloud Inc.
+  Copyright (C) 2015 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,
index 086eab3..e66e675 100644 (file)
@@ -3,7 +3,7 @@
   ownCloud Android client application\r
 \r
   Copyright (C) 2012  Bartek Przybylski\r
-  Copyright (C) 2012-2013 ownCloud Inc.\r
+  Copyright (C) 2015 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
index c96ea9a..4529965 100644 (file)
@@ -3,7 +3,7 @@
   ownCloud Android client application
 
   Copyright (C) 2012  Bartek Przybylski
-  Copyright (C) 2012-2013 ownCloud Inc.
+  Copyright (C) 2015 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,
index 4438ebf..1cb18e3 100644 (file)
@@ -3,7 +3,7 @@
   ownCloud Android client application
 
   Copyright (C) 2012  Bartek Przybylski
-  Copyright (C) 2012-2013 ownCloud Inc.
+  Copyright (C) 2015 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,
index 680e848..6647158 100644 (file)
@@ -3,7 +3,7 @@
   ownCloud Android client application\r
 \r
   Copyright (C) 2012  Bartek Przybylski\r
-  Copyright (C) 2012-2013 ownCloud Inc.\r
+  Copyright (C) 2015 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
index 773b51d..19bb0ef 100644 (file)
@@ -3,7 +3,7 @@
   ownCloud Android client application
 
   Copyright (C) 2012  Bartek Przybylski
-  Copyright (C) 2012-2013 ownCloud Inc.
+  Copyright (C) 2015 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,
index 35df55f..0c58f65 100644 (file)
Binary files a/res/drawable-hdpi/copy_link.png and b/res/drawable-hdpi/copy_link.png differ
index 1cb4d85..d95f724 100644 (file)
Binary files a/res/drawable-hdpi/ic_favorite.png and b/res/drawable-hdpi/ic_favorite.png differ
index 222172a..9ec18ce 100644 (file)
Binary files a/res/drawable-hdpi/shared_with_me.png and b/res/drawable-hdpi/shared_with_me.png differ
index a3c42a9..f4279f3 100644 (file)
Binary files a/res/drawable-hdpi/sharedlink.png and b/res/drawable-hdpi/sharedlink.png differ
index b3caf52..7384309 100644 (file)
Binary files a/res/drawable-ldpi/copy_link.png and b/res/drawable-ldpi/copy_link.png differ
index 4e2af28..6bac9b9 100644 (file)
Binary files a/res/drawable-mdpi/copy_link.png and b/res/drawable-mdpi/copy_link.png differ
index dead474..487b89d 100644 (file)
Binary files a/res/drawable-mdpi/ic_favorite.png and b/res/drawable-mdpi/ic_favorite.png differ
index 8300eac..0b17c76 100644 (file)
Binary files a/res/drawable-mdpi/shared_with_me.png and b/res/drawable-mdpi/shared_with_me.png differ
index 772838a..1d27294 100644 (file)
Binary files a/res/drawable-mdpi/sharedlink.png and b/res/drawable-mdpi/sharedlink.png differ
index c69eb05..45acfc4 100644 (file)
Binary files a/res/drawable-xhdpi/copy_link.png and b/res/drawable-xhdpi/copy_link.png differ
diff --git a/res/drawable-xhdpi/file.png b/res/drawable-xhdpi/file.png
new file mode 100644 (file)
index 0000000..d249e5f
Binary files /dev/null and b/res/drawable-xhdpi/file.png differ
diff --git a/res/drawable-xhdpi/file_doc.png b/res/drawable-xhdpi/file_doc.png
new file mode 100644 (file)
index 0000000..a8c10c8
Binary files /dev/null and b/res/drawable-xhdpi/file_doc.png differ
diff --git a/res/drawable-xhdpi/file_image.png b/res/drawable-xhdpi/file_image.png
new file mode 100644 (file)
index 0000000..84b2803
Binary files /dev/null and b/res/drawable-xhdpi/file_image.png differ
diff --git a/res/drawable-xhdpi/file_movie.png b/res/drawable-xhdpi/file_movie.png
new file mode 100644 (file)
index 0000000..bd84c72
Binary files /dev/null and b/res/drawable-xhdpi/file_movie.png differ
diff --git a/res/drawable-xhdpi/file_pdf.png b/res/drawable-xhdpi/file_pdf.png
new file mode 100644 (file)
index 0000000..e272562
Binary files /dev/null and b/res/drawable-xhdpi/file_pdf.png differ
diff --git a/res/drawable-xhdpi/file_ppt.png b/res/drawable-xhdpi/file_ppt.png
new file mode 100644 (file)
index 0000000..c898895
Binary files /dev/null and b/res/drawable-xhdpi/file_ppt.png differ
diff --git a/res/drawable-xhdpi/file_sound.png b/res/drawable-xhdpi/file_sound.png
new file mode 100644 (file)
index 0000000..82fbc7b
Binary files /dev/null and b/res/drawable-xhdpi/file_sound.png differ
diff --git a/res/drawable-xhdpi/file_xls.png b/res/drawable-xhdpi/file_xls.png
new file mode 100644 (file)
index 0000000..2e98d6c
Binary files /dev/null and b/res/drawable-xhdpi/file_xls.png differ
diff --git a/res/drawable-xhdpi/file_zip.png b/res/drawable-xhdpi/file_zip.png
new file mode 100644 (file)
index 0000000..28130ec
Binary files /dev/null and b/res/drawable-xhdpi/file_zip.png differ
diff --git a/res/drawable-xhdpi/folder_public.png b/res/drawable-xhdpi/folder_public.png
new file mode 100644 (file)
index 0000000..7680712
Binary files /dev/null and b/res/drawable-xhdpi/folder_public.png differ
index c187f0c..8a777a4 100644 (file)
Binary files a/res/drawable-xhdpi/ic_favorite.png and b/res/drawable-xhdpi/ic_favorite.png differ
diff --git a/res/drawable-xhdpi/ic_menu_archive.png b/res/drawable-xhdpi/ic_menu_archive.png
new file mode 100644 (file)
index 0000000..3ee6028
Binary files /dev/null and b/res/drawable-xhdpi/ic_menu_archive.png differ
index 3879663..ef7779c 100644 (file)
Binary files a/res/drawable-xhdpi/shared_with_me.png and b/res/drawable-xhdpi/shared_with_me.png differ
diff --git a/res/drawable-xhdpi/shared_with_me_folder.png b/res/drawable-xhdpi/shared_with_me_folder.png
new file mode 100644 (file)
index 0000000..060728c
Binary files /dev/null and b/res/drawable-xhdpi/shared_with_me_folder.png differ
index 9ef8f3e..11f8afa 100644 (file)
Binary files a/res/drawable-xhdpi/sharedlink.png and b/res/drawable-xhdpi/sharedlink.png differ
index dd27833..25fcd40 100644 (file)
@@ -3,7 +3,7 @@
   ownCloud Android client application\r
 \r
   Copyright (C) 2012  Bartek Przybylski\r
-  Copyright (C) 2012-2013 ownCloud Inc.\r
+  Copyright (C) 2015 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
index 0b0a399..ec8ccee 100644 (file)
@@ -3,7 +3,7 @@
   ownCloud Android client application
 
   Copyright (C) 2012  Bartek Przybylski
-  Copyright (C) 2012-2013 ownCloud Inc.
+  Copyright (C) 2015 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,
index 1a47be5..a9d8cdc 100644 (file)
@@ -3,7 +3,7 @@
   ownCloud Android client application
 
   Copyright (C) 2012  Bartek Przybylski
-  Copyright (C) 2012-2013 ownCloud Inc.
+  Copyright (C) 2015 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,
index bc138c7..ab90d28 100644 (file)
@@ -3,7 +3,7 @@
   ownCloud Android client application
 
   Copyright (C) 2012  Bartek Przybylski
-  Copyright (C) 2012-2013 ownCloud Inc.
+  Copyright (C) 2015 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,
index 7c49554..e735542 100644 (file)
Binary files a/res/drawable/downloading_file_indicator.png and b/res/drawable/downloading_file_indicator.png differ
index e0e86b3..7d193c3 100644 (file)
@@ -3,7 +3,7 @@
   ownCloud Android client application
 
   Copyright (C) 2012  Bartek Przybylski
-  Copyright (C) 2012-2013 ownCloud Inc.
+  Copyright (C) 2015 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,
index 8cd82e4..f3544df 100644 (file)
@@ -3,7 +3,7 @@
   ownCloud Android client application
 
   Copyright (C) 2012  Bartek Przybylski
-  Copyright (C) 2012-2013 ownCloud Inc.
+  Copyright (C) 2015 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,
index 1233647..d1ce788 100644 (file)
@@ -3,7 +3,7 @@
   ownCloud Android client application
 
   Copyright (C) 2012  Bartek Przybylski
-  Copyright (C) 2012-2013 ownCloud Inc.
+  Copyright (C) 2015 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,
index 99219b6..b449e7f 100644 (file)
@@ -3,7 +3,7 @@
   ownCloud Android client application
 
   Copyright (C) 2012  Bartek Przybylski
-  Copyright (C) 2012-2013 ownCloud Inc.
+  Copyright (C) 2015 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,
index 1e53367..bc9cdbd 100644 (file)
@@ -3,7 +3,7 @@
   ownCloud Android client application
 
   Copyright (C) 2012  Bartek Przybylski
-  Copyright (C) 2012-2013 ownCloud Inc.
+  Copyright (C) 2015 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,
index 88b1ab3..61ca2dd 100644 (file)
@@ -3,7 +3,7 @@
   ownCloud Android client application\r
 \r
   Copyright (C) 2012  Bartek Przybylski\r
-  Copyright (C) 2012-2013 ownCloud Inc.\r
+  Copyright (C) 2015 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
@@ -32,7 +32,7 @@
         android:orientation="horizontal" >\r
         \r
                <ImageView\r
-                       android:id="@+id/imageView1"\r
+                       android:id="@+id/thumbnail"\r
                        android:layout_width="0dp"\r
                        android:layout_height="wrap_content"\r
                        android:layout_weight="1"\r
index 95c7dfc..a85c3ee 100644 (file)
@@ -2,7 +2,7 @@
 <!--
   ownCloud Android client application
 
-  Copyright (C) 2012-2014 ownCloud Inc.
+  Copyright (C) 2015 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,
index f4d4fab..c67b9a9 100644 (file)
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- 
     ownCloud Android client application
-    Copyright (C) 2014 ownCloud Inc.
+    Copyright (C) 2015 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,
index fcf5429..bd4b0b6 100644 (file)
@@ -2,7 +2,7 @@
 <!-- 
   ownCloud Android client application
 
-  Copyright (C) 2012-2013 ownCloud Inc.
+  Copyright (C) 2015 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,
index e3321f9..830dd55 100644 (file)
@@ -3,7 +3,7 @@
   ownCloud Android client application\r
 \r
   Copyright (C) 2012  Bartek Przybylski\r
-  Copyright (C) 2012-2013 ownCloud Inc.\r
+  Copyright (C) 2015 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
@@ -35,7 +35,7 @@
         android:padding="8dp" >\r
 \r
         <ImageView\r
-            android:id="@+id/imageView1"\r
+            android:id="@+id/thumbnail"\r
             android:layout_width="match_parent"\r
             android:layout_height="wrap_content"\r
             android:layout_marginBottom="10dp"\r
index 0951958..940c3bc 100644 (file)
@@ -3,7 +3,7 @@
   ownCloud Android client application\r
 \r
   Copyright (C) 2012  Bartek Przybylski\r
-  Copyright (C) 2012-2013 ownCloud Inc.\r
+  Copyright (C) 2015 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
index b917600..9297bcd 100644 (file)
@@ -2,7 +2,7 @@
 <!--
   ownCloud Android client application
 
-  Copyright (C) 2012-2014 ownCloud Inc.
+  Copyright (C) 2015 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,
index 500945b..875a40c 100644 (file)
@@ -3,7 +3,7 @@
     ownCloud Android client application
 
     Copyright (C) 2012  Bartek Przybylski
-    Copyright (C) 2012-2013 ownCloud Inc.
+    Copyright (C) 2015 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,
index 56438e9..5d16b07 100644 (file)
@@ -3,7 +3,7 @@
   ownCloud Android client application
 
   Copyright (C) 2012  Bartek Przybylski
-  Copyright (C) 2012-2013 ownCloud Inc.
+  Copyright (C) 2015 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,
index db41532..93983c2 100644 (file)
@@ -3,7 +3,7 @@
   ownCloud Android client application
 
   Copyright (C) 2012  Bartek Przybylski
-  Copyright (C) 2012-2013 ownCloud Inc.
+  Copyright (C) 2015 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,
index 8f571dc..0494b8a 100644 (file)
@@ -2,7 +2,7 @@
 <!--
   ownCloud Android client application
 
-  Copyright (C) 2012-2013  ownCloud Inc.
+  Copyright (C) 2015  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.
index 483a369..d371e10 100644 (file)
@@ -2,7 +2,7 @@
 <!--
   ownCloud Android client application
 
-  Copyright (C) 2012-2013  ownCloud Inc.
+  Copyright (C) 2015 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,
index 50bc105..5d62c13 100644 (file)
@@ -3,7 +3,7 @@
   ownCloud Android client application\r
 \r
   Copyright (C) 2012  Bartek Przybylski\r
-  Copyright (C) 2012-2013 ownCloud Inc.\r
+  Copyright (C) 2015 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
index 6db8377..0b11589 100644 (file)
@@ -1,4 +1,21 @@
 <?xml version="1.0" encoding="utf-8"?>
+    <!--
+  ownCloud Android client application
+
+  Copyright (C) 2015 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"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
index 183f926..e684397 100644 (file)
@@ -2,7 +2,7 @@
 <!-- 
   ownCloud Android client application
 
-  Copyright (C) 2012-2013 ownCloud Inc.
+  Copyright (C) 2015 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,
diff --git a/res/layout/grid_image.xml b/res/layout/grid_image.xml
new file mode 100644 (file)
index 0000000..383c615
--- /dev/null
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<!--\r
+  ownCloud Android client application\r
+  Copyright (C) 2015 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
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"\r
+    android:id="@+id/ListItemLayout"\r
+    android:layout_width="match_parent"\r
+    android:layout_height="match_parent"\r
+    android:layout_gravity="center_horizontal"\r
+    android:background="@drawable/list_selector"\r
+    android:gravity="center_horizontal"\r
+    android:orientation="vertical" >\r
+\r
+    <FrameLayout\r
+        android:layout_width="match_parent"\r
+        android:layout_height="wrap_content" >\r
+\r
+        <com.owncloud.android.ui.SquareImageView\r
+            android:id="@+id/thumbnail"\r
+            android:layout_width="match_parent"\r
+            android:layout_height="match_parent"\r
+            android:paddingLeft="10dp"\r
+            android:paddingRight="10dp"\r
+            android:scaleType="centerCrop"\r
+            android:src="@drawable/ic_menu_archive"/>\r
+\r
+        <LinearLayout\r
+            android:layout_width="wrap_content"\r
+            android:layout_height="wrap_content"\r
+            android:layout_gravity="top|right"\r
+            android:orientation="vertical"\r
+            android:layout_margin="4dp">\r
+\r
+            <ImageView\r
+                android:id="@+id/sharedIcon"\r
+                android:layout_width="wrap_content"\r
+                android:layout_height="wrap_content"\r
+                android:layout_gravity="center"\r
+                android:layout_marginBottom="4dp"\r
+                android:src="@drawable/sharedlink" />\r
+\r
+            <ImageView\r
+                android:id="@+id/sharedWithMeIcon"\r
+                android:layout_width="wrap_content"\r
+                android:layout_height="wrap_content"\r
+                android:layout_gravity="center"\r
+                android:layout_marginTop="4dp"\r
+                android:src="@drawable/shared_with_me"\r
+                android:visibility="invisible" />\r
+        </LinearLayout>\r
+\r
+        <ImageView\r
+            android:id="@+id/localFileIndicator"\r
+            android:layout_width="@dimen/file_icon_size"\r
+            android:layout_height="@dimen/file_icon_size"\r
+            android:layout_gravity="bottom|right"\r
+            android:layout_marginTop="4dp"\r
+            android:layout_marginBottom="4dp"\r
+            android:layout_marginRight="4dp"\r
+            android:src="@drawable/local_file_indicator" />\r
+\r
+        <ImageView\r
+            android:id="@+id/favoriteIcon"\r
+            android:layout_width="15dp"\r
+            android:layout_height="15dp"\r
+            android:layout_gravity="bottom|right"\r
+            android:layout_marginBottom="4dp"\r
+            android:layout_marginRight="4dp"\r
+            android:src="@drawable/ic_favorite" />\r
+    </FrameLayout>\r
+\r
+</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/grid_item.xml b/res/layout/grid_item.xml
new file mode 100644 (file)
index 0000000..d0f3d0f
--- /dev/null
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<!--\r
+  ownCloud Android client application\r
+  Copyright (C) 2015 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
+<com.owncloud.android.ui.SquareLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"\r
+    android:id="@+id/ListItemLayout"\r
+    android:layout_width="match_parent"\r
+    android:layout_height="match_parent"\r
+    android:layout_gravity="center_horizontal"\r
+    android:background="@drawable/list_selector"\r
+    android:gravity="center"\r
+    android:orientation="vertical" >\r
+\r
+    <FrameLayout\r
+        android:layout_width="match_parent"\r
+        android:layout_height="wrap_content"\r
+        android:layout_gravity="center_horizontal" >\r
+\r
+        <ImageView\r
+            android:id="@+id/thumbnail"\r
+            android:layout_width="72dp"\r
+            android:layout_height="72dp"\r
+            android:layout_gravity="center_horizontal"\r
+            android:layout_marginLeft="10dp"\r
+            android:layout_marginRight="10dp"\r
+            android:src="@drawable/ic_menu_archive" />\r
+\r
+        <LinearLayout\r
+            android:layout_width="wrap_content"\r
+            android:layout_height="wrap_content"\r
+            android:layout_gravity="top|right"\r
+            android:orientation="vertical"\r
+            android:layout_margin="2dp">\r
+\r
+            <ImageView\r
+                android:id="@+id/sharedIcon"\r
+                android:layout_width="wrap_content"\r
+                android:layout_height="wrap_content"\r
+                android:layout_gravity="center"\r
+                android:layout_marginBottom="2dp"\r
+                android:src="@drawable/sharedlink" />\r
+\r
+            <ImageView\r
+                android:id="@+id/sharedWithMeIcon"\r
+                android:layout_width="wrap_content"\r
+                android:layout_height="wrap_content"\r
+                android:layout_gravity="center"\r
+                android:layout_marginTop="2dp"\r
+                android:src="@drawable/shared_with_me"\r
+                android:visibility="invisible" />\r
+        </LinearLayout>\r
+\r
+        <ImageView\r
+            android:id="@+id/localFileIndicator"\r
+            android:layout_width="@dimen/file_icon_size"\r
+            android:layout_height="@dimen/file_icon_size"\r
+            android:layout_gravity="bottom|right"\r
+            android:layout_marginTop="2dp"\r
+            android:layout_marginRight="2dp"\r
+            android:src="@drawable/local_file_indicator" />\r
+\r
+        <ImageView\r
+            android:id="@+id/favoriteIcon"\r
+            android:layout_width="15dp"\r
+            android:layout_height="15dp"\r
+            android:layout_gravity="bottom|right"\r
+            android:layout_marginBottom="2dp"\r
+            android:layout_marginRight="2dp"\r
+            android:src="@drawable/ic_favorite" />\r
+\r
+\r
+\r
+    </FrameLayout>\r
+\r
+    <TextView\r
+        android:id="@+id/Filename"\r
+        android:layout_width="match_parent"\r
+        android:layout_height="wrap_content"\r
+        android:layout_marginLeft="4dp"\r
+        android:layout_marginRight="4dp"\r
+        android:ellipsize="middle"\r
+        android:gravity="center_horizontal"\r
+        android:singleLine="true"\r
+        android:text="TextView"\r
+        android:textColor="@color/textColor"\r
+        android:textSize="16dip" />\r
+\r
+</com.owncloud.android.ui.SquareLinearLayout>
\ No newline at end of file
index 160edc1..81b5210 100644 (file)
@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- 
+<!--
   ownCloud Android client application
 
   Copyright (C) 2012  Bartek Przybylski
-  Copyright (C) 2012-2013 ownCloud Inc.
+  Copyright (C) 2015 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,
 
   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
- -->
+-->
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-       android:layout_width="0dp"
-       android:layout_height="match_parent"
-       android:layout_weight="1" >
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:layout_weight="1" >
 
     <android.support.v4.widget.SwipeRefreshLayout
-        android:id="@+id/swipe_refresh_files"
+        android:id="@+id/swipe_containing_list"
         android:layout_width="match_parent"
         android:layout_height="match_parent" 
         android:layout_weight="1"
-        android:footerDividersEnabled="false" > 
+        android:footerDividersEnabled="false"
+        android:visibility="visible" >
         
         <com.owncloud.android.ui.ExtendedListView
             android:id="@+id/list_root"
             android:layout_width="match_parent"
-            android:layout_height="match_parent" />
-            
+            android:layout_height="match_parent"
+            android:visibility="visible" />
+
     </android.support.v4.widget.SwipeRefreshLayout>
-       
-       <android.support.v4.widget.SwipeRefreshLayout
-        android:id="@+id/swipe_refresh_files_emptyView"
+
+    <android.support.v4.widget.SwipeRefreshLayout
+        android:id="@+id/swipe_containing_grid"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
+        android:layout_weight="1"
+        android:footerDividersEnabled="false"
         android:visibility="gone" >
 
-        <ScrollView
+        <third_parties.in.srain.cube.GridViewWithHeaderAndFooter
+            android:id="@+id/grid_root"
             android:layout_width="match_parent"
-            android:layout_height="match_parent" >
-
-                   <TextView
-                               android:id="@+id/empty_list_view"
-                               android:layout_width="match_parent"
-                               android:layout_height="wrap_content"
-                               android:gravity="center_vertical|center_horizontal"
-                               android:text="@string/empty"
-                                       android:layout_gravity="center"
-                               android:visibility="visible" />
-
-        </ScrollView>
+            android:layout_height="match_parent"
+            android:columnWidth="100dp"
+            android:gravity="center"
+            android:horizontalSpacing="2dp"
+            android:stretchMode="columnWidth"
+            android:verticalSpacing="2dp"
+            android:visibility="visible" />
+
+    </android.support.v4.widget.SwipeRefreshLayout>
+
+    <android.support.v4.widget.SwipeRefreshLayout
+        android:id="@+id/swipe_containing_empty"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:visibility="gone" >
+            <ScrollView
+                android:layout_width="match_parent"
+                android:layout_height="match_parent" >
+                <TextView
+                    android:id="@+id/empty_list_view"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_gravity="center"
+                    android:gravity="center_vertical|center_horizontal"
+                    android:text="@string/empty"
+                    android:visibility="visible" />
+            </ScrollView>
     </android.support.v4.widget.SwipeRefreshLayout>
-</FrameLayout>
+
+</FrameLayout>
\ No newline at end of file
index c6c7b92..c66ff73 100644 (file)
@@ -3,7 +3,7 @@
   ownCloud Android client application\r
 \r
   Copyright (C) 2012  Bartek Przybylski\r
-  Copyright (C) 2012-2013 ownCloud Inc.\r
+  Copyright (C) 2015 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
  -->\r
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"\r
     android:id="@+id/ListItemLayout"\r
-    android:layout_width="fill_parent"\r
+    android:layout_width="match_parent"\r
     android:background="@drawable/list_selector"\r
-    android:orientation="horizontal"\r
+    android:orientation="vertical"\r
     android:layout_height="56dp">\r
 \r
-    <FrameLayout\r
-        android:layout_width="56dp"\r
-        android:layout_height="56dp"\r
-        android:focusable="false"\r
-        android:focusableInTouchMode="false">\r
-\r
-        <ImageView\r
-            android:id="@+id/imageView2"\r
-            android:layout_width="@dimen/file_icon_size"\r
-            android:layout_height="@dimen/file_icon_size"\r
-            android:layout_gravity="center_vertical"\r
-            android:layout_marginLeft="22dp"\r
-            android:src="@drawable/local_file_indicator" />\r
-\r
-        <ImageView\r
-            android:id="@+id/imageView1"\r
-            android:layout_width="@dimen/file_icon_size"\r
-            android:layout_height="@dimen/file_icon_size"\r
-            android:layout_gravity="center_vertical"\r
-            android:layout_marginLeft="9dp"\r
-            android:src="@drawable/ic_menu_archive" />\r
-\r
-        <ImageView\r
-            android:id="@+id/imageView3"\r
-            android:layout_width="wrap_content"\r
-            android:layout_height="wrap_content"\r
-            android:layout_gravity="bottom|right"\r
-            android:layout_marginBottom="10dp"\r
-            android:layout_marginRight="2dp"\r
-            android:src="@drawable/ic_favorite" />\r
-    </FrameLayout>\r
-\r
     <LinearLayout\r
-        android:layout_width="0dp"\r
+        android:layout_width="match_parent"\r
         android:layout_height="match_parent"\r
-        android:layout_weight="1"\r
-        android:gravity="center_vertical"\r
-        android:orientation="vertical" >\r
-\r
-        <TextView\r
-            android:id="@+id/Filename"\r
-            android:layout_width="wrap_content"\r
-            android:layout_height="wrap_content"\r
-            android:layout_gravity="center_vertical"\r
-            android:layout_marginLeft="4dp"\r
-            android:layout_marginRight="4dp"\r
-            android:ellipsize="middle"\r
-            android:singleLine="true"\r
-            android:text="TextView"\r
-            android:textColor="#303030"\r
-            android:textSize="16dip" />\r
+        android:orientation="horizontal">\r
+\r
+        <FrameLayout\r
+            android:layout_width="56dp"\r
+            android:layout_height="56dp"\r
+            android:focusable="false"\r
+            android:focusableInTouchMode="false">\r
+\r
+            <ImageView\r
+                android:id="@+id/localFileIndicator"\r
+                android:layout_width="@dimen/file_icon_size"\r
+                android:layout_height="@dimen/file_icon_size"\r
+                android:layout_gravity="center_vertical"\r
+                android:layout_marginLeft="22dp"\r
+                android:src="@drawable/local_file_indicator" />\r
+\r
+            <ImageView\r
+                android:id="@+id/thumbnail"\r
+                android:layout_width="@dimen/file_icon_size"\r
+                android:layout_height="@dimen/file_icon_size"\r
+                android:layout_gravity="center_vertical"\r
+                android:layout_marginLeft="9dp"\r
+                android:src="@drawable/ic_menu_archive" />\r
+\r
+            <ImageView\r
+                android:id="@+id/favoriteIcon"\r
+                android:layout_width="wrap_content"\r
+                android:layout_height="wrap_content"\r
+                android:layout_gravity="bottom|right"\r
+                android:layout_marginBottom="10dp"\r
+                android:layout_marginRight="2dp"\r
+                android:src="@drawable/ic_favorite" />\r
+        </FrameLayout>\r
 \r
         <LinearLayout\r
-            android:layout_width="match_parent"\r
-            android:layout_height="wrap_content"\r
-            android:layout_marginLeft="4dp"\r
-            android:layout_marginRight="4dp"\r
-            android:weightSum="1">\r
+            android:layout_width="0dp"\r
+            android:layout_height="match_parent"\r
+            android:layout_weight="1"\r
+            android:gravity="center_vertical"\r
+            android:orientation="vertical" >\r
 \r
             <TextView\r
-                android:id="@+id/last_mod"\r
+                android:id="@+id/Filename"\r
                 android:layout_width="wrap_content"\r
                 android:layout_height="wrap_content"\r
+                android:layout_gravity="center_vertical"\r
+                android:layout_marginLeft="4dp"\r
+                android:layout_marginRight="4dp"\r
+                android:ellipsize="middle"\r
+                android:singleLine="true"\r
                 android:text="TextView"\r
-                android:layout_weight=".5"\r
-                android:textColor="@color/list_item_lastmod_and_filesize_text"\r
-                android:textSize="12dip"/>\r
+                android:textColor="#303030"\r
+                android:textSize="16dip" />\r
 \r
-            <TextView\r
-                android:id="@+id/file_size"\r
-                android:layout_width="wrap_content"\r
+            <LinearLayout\r
+                android:layout_width="match_parent"\r
                 android:layout_height="wrap_content"\r
-                android:gravity="right"\r
-                android:text="TextView"\r
-                android:textColor="@color/list_item_lastmod_and_filesize_text"\r
-                android:layout_weight=".5"\r
-                android:textSize="12dip"/>\r
+                android:layout_marginLeft="4dp"\r
+                android:layout_marginRight="4dp"\r
+                android:weightSum="1">\r
+\r
+                <TextView\r
+                    android:id="@+id/last_mod"\r
+                    android:layout_width="wrap_content"\r
+                    android:layout_height="wrap_content"\r
+                    android:text="TextView"\r
+                    android:layout_weight=".5"\r
+                    android:textColor="@color/list_item_lastmod_and_filesize_text"\r
+                    android:textSize="12dip"/>\r
+\r
+                <TextView\r
+                    android:id="@+id/file_size"\r
+                    android:layout_width="wrap_content"\r
+                    android:layout_height="wrap_content"\r
+                    android:gravity="right"\r
+                    android:text="TextView"\r
+                    android:textColor="@color/list_item_lastmod_and_filesize_text"\r
+                    android:layout_weight=".5"\r
+                    android:textSize="12dip"/>\r
+\r
+            </LinearLayout>\r
 \r
         </LinearLayout>\r
 \r
-    </LinearLayout>\r
+        <LinearLayout\r
+            android:layout_width="25dp"\r
+            android:layout_height="match_parent"\r
+            android:gravity="center_vertical"\r
+            android:orientation="vertical">\r
 \r
-    <LinearLayout\r
-        android:layout_width="25dp"\r
-        android:layout_height="match_parent"\r
-        android:gravity="center_vertical"\r
-        android:orientation="vertical">\r
-\r
-    <ImageView\r
-        android:id="@+id/sharedIcon"\r
-        android:layout_width="wrap_content"\r
-        android:layout_height="wrap_content"\r
-        android:layout_gravity="center"\r
-        android:layout_marginLeft="4dp"\r
-        android:layout_marginBottom="4dp"\r
-        android:layout_marginRight="4dp"\r
-        android:src="@drawable/sharedlink" />\r
-\r
-    <ImageView\r
-        android:id="@+id/sharedWithMeIcon"\r
-        android:layout_width="wrap_content"\r
-        android:layout_height="wrap_content"\r
-        android:layout_gravity="center"\r
-        android:layout_marginLeft="4dp"\r
-        android:layout_marginRight="4dp"\r
-        android:layout_marginTop="4dp"\r
-        android:src="@drawable/shared_with_me" />\r
+            <ImageView\r
+                android:id="@+id/sharedIcon"\r
+                android:layout_width="wrap_content"\r
+                android:layout_height="wrap_content"\r
+                android:layout_gravity="center"\r
+                android:layout_marginLeft="4dp"\r
+                android:layout_marginBottom="4dp"\r
+                android:layout_marginRight="4dp"\r
+                android:src="@drawable/sharedlink" />\r
+\r
+            <ImageView\r
+                android:id="@+id/sharedWithMeIcon"\r
+                android:layout_width="wrap_content"\r
+                android:layout_height="wrap_content"\r
+                android:layout_gravity="center"\r
+                android:layout_marginLeft="4dp"\r
+                android:layout_marginRight="4dp"\r
+                android:layout_marginTop="4dp"\r
+                android:src="@drawable/shared_with_me"\r
+                android:visibility="invisible" />\r
 \r
+        </LinearLayout>\r
+\r
+        <ImageView\r
+            android:id="@+id/custom_checkbox"\r
+            android:layout_width="wrap_content"\r
+            android:layout_height="wrap_content"\r
+            android:layout_gravity="center_vertical"\r
+            android:layout_marginLeft="4dp"\r
+            android:layout_marginRight="4dp"\r
+            android:gravity=""\r
+            android:src="@android:drawable/checkbox_off_background" />\r
     </LinearLayout>\r
 \r
-    <ImageView\r
-        android:id="@+id/custom_checkbox"\r
-        android:layout_width="wrap_content"\r
-        android:layout_height="wrap_content"\r
-        android:layout_gravity="center_vertical"\r
-        android:layout_marginLeft="4dp"\r
-        android:layout_marginRight="4dp"\r
-        android:gravity=""\r
-        android:src="@android:drawable/checkbox_off_background" />\r
+    <View\r
+        android:layout_width="match_parent"\r
+        android:layout_height="1dp"\r
+        android:background="@color/list_divider_background"></View>\r
 \r
 </LinearLayout>\r
index 629d8e2..0dbb9ef 100644 (file)
@@ -1,4 +1,21 @@
 <?xml version="1.0" encoding="utf-8"?>
+<!--
+  ownCloud Android client application
+
+  Copyright (C) 2015 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"
     android:id="@+id/loadingLayout"
     android:layout_width="match_parent"
index d9326ff..2353b19 100644 (file)
@@ -1,4 +1,21 @@
 <?xml version="1.0" encoding="utf-8"?>
+<!--
+  ownCloud Android client application
+
+  Copyright (C) 2015 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"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
index 6f129eb..756a2ed 100644 (file)
@@ -1,4 +1,21 @@
 <?xml version="1.0" encoding="utf-8"?>
+<!--
+  ownCloud Android client application
+
+  Copyright (C) 2015 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"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
index f308edc..27900c4 100644 (file)
@@ -2,7 +2,7 @@
 <!--
   ownCloud Android client application
 
-  Copyright (C) 2012-2013  ownCloud Inc.
+  Copyright (C) 2015  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,
index 1df31dc..ae2dbfa 100644 (file)
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- 
     ownCloud Android client application
-    Copyright (C) 2014 ownCloud Inc.
+    Copyright (C) 2015 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,
diff --git a/res/layout/password_dialog.xml b/res/layout/password_dialog.xml
new file mode 100644 (file)
index 0000000..b81e40b
--- /dev/null
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    ownCloud Android client application
+
+    Copyright (C) 2015 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"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <EditText
+        android:id="@+id/share_password"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:ems="10"
+               android:inputType="textPassword">
+    </EditText>
+
+</LinearLayout>
\ No newline at end of file
index b2cf5df..8c95c72 100644 (file)
@@ -3,7 +3,7 @@
   ownCloud Android client application\r
 \r
   Copyright (C) 2012  Bartek Przybylski\r
-  Copyright (C) 2012-2013 ownCloud Inc.\r
+  Copyright (C) 2015 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
@@ -34,7 +34,8 @@
         android:textColor="@android:color/black"\r
         android:gravity="center_horizontal"\r
          />\r
-\r    <TextView\r
+\r
+    <TextView\r
         android:id="@+id/pinHdrExpl"\r
         android:layout_width="wrap_content"\r
         android:layout_height="wrap_content"\r
index ad0676b..52dadd7 100644 (file)
@@ -3,7 +3,7 @@
   ownCloud Android client application\r
 \r
   Copyright (C) 2012  Bartek Przybylski\r
-  Copyright (C) 2012-2013 ownCloud Inc.\r
+  Copyright (C) 2015 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
index d712b7f..9baf6c2 100644 (file)
@@ -2,7 +2,7 @@
 <!--
   ownCloud Android client application
 
-  Copyright (C) 2012-2013  ownCloud Inc.
+  Copyright (C) 2015 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,
index 9467d34..611351b 100644 (file)
@@ -2,7 +2,7 @@
 <!--
   ownCloud Android client application
 
-  Copyright (C) 2012-2013  ownCloud Inc.
+  Copyright (C) 2015  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,
@@ -43,7 +43,7 @@
         android:layout_centerInParent="true"
         />
     
-    <com.owncloud.android.utils.TouchImageViewCustom
+    <third_parties.michaelOrtiz.TouchImageViewCustom
         android:id="@+id/image"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
index 6a30c2e..813d677 100644 (file)
@@ -2,7 +2,7 @@
 <!-- 
     ownCloud Android client application
 
-    Copyright (C) 2012-2013 ownCloud Inc.
+    Copyright (C) 2015 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,
index 27204a2..f3153b3 100644 (file)
@@ -2,7 +2,7 @@
 <!-- 
     ownCloud Android client application
 
-    Copyright (C) 2012-2013 ownCloud Inc.
+    Copyright (C) 2015 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,
index ccfb04b..652acb4 100644 (file)
@@ -2,7 +2,7 @@
 <!--
   ownCloud Android client application
 
-  Copyright (C) 2012-2013 ownCloud Inc.
+  Copyright (C) 2015 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,
index 6c15ff7..42bdcdd 100644 (file)
@@ -2,7 +2,7 @@
 <!-- \r
   ownCloud Android client application\r
 \r
-  Copyright (C) 2012-2013 ownCloud Inc.\r
+  Copyright (C) 2015 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
     android:layout_height="fill_parent"\r
     android:background="@color/background_color"\r
     android:orientation="vertical" >\r
-
+\r
     <fragment\r
         android:id="@+id/local_files_list"\r
         android:layout_width="match_parent"\r
         android:layout_height="0dip"\r
         android:layout_weight="1"\r
         class="com.owncloud.android.ui.fragment.LocalFileListFragment" />\r
-
+\r
     <LinearLayout\r
         android:layout_width="match_parent"\r
         android:layout_height="wrap_content"\r
         android:gravity="center"\r
         android:orientation="horizontal" >\r
-\r        <Button\r
+\r
+        <Button\r
             android:id="@+id/upload_files_btn_cancel"\r
             android:layout_width="wrap_content"\r
             android:layout_height="wrap_content"\r
             android:layout_weight="1"\r
             android:text="@string/common_cancel" />\r
-\r              <Button\r
+\r
+               <Button\r
                    android:id="@+id/upload_files_btn_upload"\r
                    android:layout_width="wrap_content"\r
                    android:layout_height="wrap_content"\r
index 3053c3e..60a2111 100644 (file)
@@ -3,7 +3,7 @@
   ownCloud Android client application
 
   Copyright (C) 2012  Bartek Przybylski
-  Copyright (C) 2012-2013 ownCloud Inc.
+  Copyright (C) 2015 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,
index 1cb9361..e093269 100644 (file)
@@ -3,7 +3,7 @@
   ownCloud Android client application
 
   Copyright (C) 2012  Bartek Przybylski
-  Copyright (C) 2012-2013 ownCloud Inc.
+  Copyright (C) 2015 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,
@@ -30,7 +30,7 @@
         android:layout_gravity="center_vertical|center"
         android:layout_margin="4dp"
         android:src="@drawable/ic_menu_archive" 
-        android:id="@+id/imageView1" />
+        android:id="@+id/thumbnail" />
     
     <TextView 
         android:text="TextView" 
index 8063ab4..ac0ca6a 100644 (file)
@@ -1,4 +1,21 @@
 <?xml version="1.0" encoding="utf-8"?>
+<!--
+  ownCloud Android client application
+
+  Copyright (C) 2015 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/>.
+-->
 <FrameLayout   xmlns:android="http://schemas.android.com/apk/res/android"
                                android:layout_width="match_parent"
                                android:layout_height="match_parent" >
index b7e2dd3..df83e37 100644 (file)
@@ -3,7 +3,7 @@
   ownCloud Android client application
 
   Copyright (C) 2012  Bartek Przybylski
-  Copyright (C) 2012-2013 ownCloud Inc.
+  Copyright (C) 2015 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,
index b60d542..545f8ea 100644 (file)
@@ -3,7 +3,7 @@
   ownCloud Android client application
 
   Copyright (C) 2012  Bartek Przybylski
-  Copyright (C) 2012-2013 ownCloud Inc.
+  Copyright (C) 2015 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,
index b738322..4f1f890 100644 (file)
@@ -3,7 +3,7 @@
   ownCloud Android client application
 
   Copyright (C) 2012  Bartek Przybylski
-  Copyright (C) 2012-2013 ownCloud Inc.
+  Copyright (C) 2015 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,
index a54a664..d651120 100644 (file)
@@ -2,7 +2,7 @@
 <!--
   ownCloud Android client application
 
-  Copyright (C) 2012-2013 ownCloud Inc.
+  Copyright (C) 2015 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,
 -->
        <body>
        <p>
-               Dieses Gerät läuft mit Android 4.1.x.
+               Dieses Ger�t l�uft mit Android 4.1.x.
        </p>
        <p>
-               In dieser Version von Android existiert ein Bug, der nach jedem Neustart eine erneute Eingabe der ownCloud Login-Informationen nötig macht. Um das zu umgehen installieren Sie bitte diese kostenlose Hilfs-App: 
+               In dieser Version von Android existiert ein Bug, der nach jedem Neustart eine erneute Eingabe der ownCloud Login-Informationen ntig macht. Um das zu umgehen installieren Sie bitte diese kostenlose Hilfs-App: 
        </p>
        <p style="text-align:center">
                <a href="http://play.google.com/store/apps/details?id=com.owncloud.android.workaround.accounts">ownCloud Jelly Bean Workaround</a> 
index 9321d52..e8f0e77 100644 (file)
@@ -2,7 +2,7 @@
 <!--
   ownCloud Android client application
 
-  Copyright (C) 2012-2013 ownCloud Inc.
+  Copyright (C) 2015 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,
@@ -21,7 +21,7 @@
                Su dispositivo ejecuta Android 4.1.x. 
        </p>
        <p>
-               Para prevenir la pérdida de las credenciales de sus cuentas ownCloud en cada reinicio, por favor, instale esta app gratuita que evita el problema en Jelly Bean:        
+               Para prevenir la p�rdida de las credenciales de sus cuentas ownCloud en cada reinicio, por favor, instale esta app gratuita que evita el problema en Jelly Bean:      
        </p>
        <p style="text-align:center">
                <a href="http://play.google.com/store/apps/details?id=com.owncloud.android.workaround.accounts">ownCloud Jelly Bean Workaround</a>
index 754cf6f..fd5a20d 100644 (file)
@@ -2,7 +2,7 @@
 <!--
   ownCloud Android client application
 
-  Copyright (C) 2012-2013 ownCloud Inc.
+  Copyright (C) 2015 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,
index d8d4eb0..49d6c3c 100644 (file)
   <string name="saml_authentication_wrong_pass">كلمة مرور خاطئة</string>
   <string name="folder_picker_choose_button_text">اختيار</string>
   <string name="prefs_category_security">الأمان</string>
-  <string name="shared_subject_header">مُشارك</string>
 </resources>
index 3f91b6d..c6c8f69 100644 (file)
   <string name="actionbar_settings">Quraşdırmalar</string>
   <string name="actionbar_see_details">Detallar</string>
   <string name="actionbar_send_file">Göndər</string>
+  <string name="actionbar_sort">Çeşidləmək</string>
+  <string name="actionbar_sort_title">Təyinata görə çeşidləmək </string>
+  <string-array name="actionbar_sortby">
+    <item>A-Z</item>
+    <item>Yenisi - Köhnəsi</item>
+  </string-array>
   <!--TODO re-enable when server-side folder size calculation is available   
        <item>Biggest - Smallest</item>-->
   <string name="prefs_category_general">Ümumi</string>
@@ -32,6 +38,8 @@
   <string name="prefs_recommend">Dostuna məsləhət gör</string>
   <string name="prefs_feedback">Geriyə cavab</string>
   <string name="prefs_imprint">İşarələmək</string>
+  <string name="prefs_remember_last_share_location">Paylaşma ünvanını yadda saxla</string>
+  <string name="prefs_remember_last_upload_location_summary">Son paylaşılmış yüklənmə ünvanını yadda saxla</string>
   <string name="recommend_subject">%1$s-i ağıllı telefonunuzda yoxlayın!</string>
   <string name="recommend_text">Mən sizi öz smartfonunuzda %1$s istifadə etmək üçün dəvət etmək istəyirəm! Burdan endirin: %2$s</string>
   <string name="auth_check_server">Serveri yoxla</string>
   <string name="uploader_wrn_no_content_text">Heç bir kontent gəlmədi. Yukləmək üçün heçnə yoxdur.</string>
   <string name="uploader_error_forbidden_content">%1$s yayımlanmış kontent üçün yetkili deyil</string>
   <string name="uploader_info_uploading">Yüklənmə gedir</string>
+  <string name="file_list_seconds_ago">saniyələr öncə</string>
   <string name="file_list_empty">Burda heçnə yoxdur. Nese yükləyin!</string>
   <string name="file_list_loading">Yüklənir...</string>
   <string name="local_file_list_empty">Bu qovluqda heç bir fayl movcud deyil.</string>
+  <string name="file_list_folder">qovluq</string>
+  <string name="file_list_folders">qovluqlar</string>
+  <string name="file_list_file">fayl</string>
+  <string name="file_list_files">fayllar</string>
   <string name="filedetails_select_file">Faylın üstünə sıxın ki, əlavə məlumat ekrana çıxsın.</string>
   <string name="filedetails_size">Həcm:</string>
   <string name="filedetails_type">Tip:</string>
@@ -177,6 +190,7 @@ Aşağıda göstərilən %5$s-də olan daxili və xarici fayl(lar) link edilmiş
   <string name="auth_unsupported_multiaccount">%1$s çoxlu hesab dəstəkləmir</string>
   <string name="auth_fail_get_user_name">Sizin server düzgün istifadəçi id-si qaytarmır, xahiş olunur inzibatçı ilə əlaqə saxlayasınız</string>
   <string name="auth_can_not_auth_against_server">Bu serverdə yenidən qeydiyyatdan keçmək olmur</string>
+  <string name="auth_account_does_not_exist">Hesab göstərilən avadanlıqda mövcud deyil</string>
   <string name="fd_keep_in_sync">Faylı gündəmdə saxla</string>
   <string name="common_rename">Adı dəyiş</string>
   <string name="common_remove">Sil</string>
@@ -206,19 +220,88 @@ Aşağıda göstərilən %5$s-də olan daxili və xarici fayl(lar) link edilmiş
   <string name="ssl_validator_reason_cert_not_trusted">Server sertifikati inamlı deyil</string>
   <string name="ssl_validator_reason_cert_expired">- Server sertifikatının vaxtı bitmişdir</string>
   <string name="ssl_validator_reason_cert_not_yet_valid">- Server sertifikatının düzgün tarixi gələcəkdədir</string>
+  <string name="ssl_validator_reason_hostname_not_verified">URL sertifikatda olan host adına uyğun deyil</string>
+  <string name="ssl_validator_question">İstənilən halda bu sertifikata inanmaq istəyirsinizmi?</string>
+  <string name="ssl_validator_not_saved">Sertifikat saxlanıla bilməz</string>
   <string name="ssl_validator_btn_details_see">Detallar</string>
+  <string name="ssl_validator_btn_details_hide">Gizlə</string>
+  <string name="ssl_validator_label_subject">Verilir:</string>
+  <string name="ssl_validator_label_issuer">Tərəfindən verilib:</string>
+  <string name="ssl_validator_label_CN">Ümumi ad:</string>
+  <string name="ssl_validator_label_O">Təşkilat:</string>
+  <string name="ssl_validator_label_OU">Alt təşkilatOrganizational unit:</string>
+  <string name="ssl_validator_label_C">Ölkə:</string>
+  <string name="ssl_validator_label_ST">Dövlət:</string>
+  <string name="ssl_validator_label_L">Ərazi:</string>
+  <string name="ssl_validator_label_validity">Etibarlılıq:</string>
+  <string name="ssl_validator_label_validity_from">Kimdən:</string>
+  <string name="ssl_validator_label_validity_to">Kimə:</string>
+  <string name="ssl_validator_label_signature">İmza:</string>
+  <string name="ssl_validator_label_signature_algorithm">Alqıritm:</string>
+  <string name="ssl_validator_null_cert">Sertifikat görünə bilməz.</string>
+  <string name="ssl_validator_no_info_about_error">- Səhv haqqında məlumat yoxdur</string>
+  <string name="placeholder_sentence">Bu bir yer doldurucusudur</string>
+  <string name="placeholder_filename">yerdoldurucusu.txt</string>
+  <string name="placeholder_filetype">PNG Şəkil</string>
+  <string name="placeholder_filesize">389 KB</string>
+  <string name="placeholder_timestamp">2012/05/18 12:23</string>
+  <string name="placeholder_media_time">12:23:45</string>
+  <string name="instant_upload_on_wifi">Şəkilləri yalnız WiFi üzərindən yüklə</string>
+  <string name="instant_video_upload_on_wifi">Videoları yalnız WiFi üzərindən yüklə</string>
+  <string name="instant_upload_path">/CəldYükləmə</string>
+  <string name="conflict_title">Yüklənmə konflikti</string>
+  <string name="conflict_message">Uzaq fayl %s local faylla sinxronizasiya edilmədi. Faylın kontentinin serverdə dəyişdirilməsinə davam edirik.</string>
+  <string name="conflict_keep_both">Birlikdə saxla</string>
+  <string name="conflict_overwrite">Sil yenidən yaz</string>
+  <string name="conflict_dont_upload">Yükləmə</string>
+  <string name="preview_image_description">Şəkili göstər</string>
+  <string name="preview_image_error_unknown_format">Bu şəkil göstərilə bilməz</string>
+  <string name="error__upload__local_file_not_copied">%1$s nüsxələnə bilməz %2$s local qovluğa</string>
+  <string name="prefs_instant_upload_path_title">Yüklənmə ünvanı</string>
+  <string name="share_link_no_support_share_api">Üzr istəyirik, sizin yerverdə paylaşıma izin verilmir. Xahiş olunur
+inzibatçınızla əlaqə saxlayasınız.</string>
+  <string name="share_link_file_no_exist">Paylaşa bilinmir.</string>
+  <string name="share_link_file_error">Bu faylın yada qovluğun paylaşımı zamanı səhv baş verdi </string>
+  <string name="unshare_link_file_no_exist">Paylaşımı dayandırmaq olmur. Xahiş olunur fayl mövcudluğunu yoxlayasınız</string>
   <string name="unshare_link_file_error">Bu fayl və ya qovluğun yayımlanmasının dayandırılmasında səhv baş verdi</string>
   <string name="activity_chooser_send_file_title">Göndər</string>
   <string name="copy_link">linki nüsxələ</string>
   <string name="clipboard_text_copied">Mübadilə buferinə nüsxələndi</string>
+  <string name="error_cant_bind_to_operations_service">Kritik səhv: əməliyyat yerinə yetirilə bilinmir</string>
+  <string name="network_error_socket_exception">Serverlə əlaqəyə girdikdə səhv baş verdi.</string>
+  <string name="network_error_socket_timeout_exception">Serveri gözlədiyimiz müddətdə səhv baş verdi, əməliyyat bitə bilməz</string>
+  <string name="network_error_connect_timeout_exception">Serveri gözlədiyimiz müddətdə səhv baş verdi, əməliyyat bitə bilməz</string>
+  <string name="network_host_not_available">Əməliyyat bitə bilməz, serverə çatmaq mümkün deyil </string>
   <string name="empty"></string>
   <string name="forbidden_permissions">Sizin yetkiniz yoxdur %s</string>
+  <string name="forbidden_permissions_rename">faylın adını dəyişmək</string>
   <string name="forbidden_permissions_delete">bu faylı silmək üçün</string>
   <string name="share_link_forbidden_permissions">bu faylı yayımlamaq üçün</string>
+  <string name="unshare_link_forbidden_permissions">fayl paylaşımını dayandırmaq</string>
   <string name="forbidden_permissions_create">fayl yaratmaq üçün</string>
   <string name="uploader_upload_forbidden_permissions">bu qovluğa yükləmək üçün</string>
+  <string name="downloader_download_file_not_found">Bu fayla serverdə artıq uzun müddətdir ki, çatmaq mümkün deyil</string>
   <string name="prefs_category_accounts">Hesablar</string>
   <string name="prefs_add_account">Hesab əlavə et</string>
+  <string name="auth_redirect_non_secure_connection_title">Təhlükəsiz qoşulma, təhlükəsiz olmayan istiqamətə yönlədirilmişdir</string>
+  <string name="actionbar_logger">Jurnallar</string>
+  <string name="log_send_history_button">Tarixçəni göndər</string>
+  <string name="log_send_no_mail_app">Jurnalların ötürülməsi üçün proqram təminatı tapılmadı!</string>
+  <string name="log_send_mail_subject">%1$s Android proqram jurnalları</string>
+  <string name="log_progress_dialog_text">Data yüklənir...</string>
+  <string name="saml_authentication_required_text">Qeydiyyat tələb edilir</string>
   <string name="saml_authentication_wrong_pass">Yalnış şifrə</string>
-  <string name="shared_subject_header">yayımlanmış</string>
+  <string name="actionbar_move">Köçürmək</string>
+  <string name="file_list_empty_moving">Burda heçnə yoxdur. Siz qovluq əlavə edə bilərsiniz!</string>
+  <string name="folder_picker_choose_button_text">Seç</string>
+  <string name="move_file_not_found">Köçürmə mümkün olmur. Xahiş olunur faylın mövcudluğunu yoxlayasınız.</string>
+  <string name="move_file_invalid_into_descendent">Qovluğu bu nəsilə köçürmək mümkün deyil</string>
+  <string name="move_file_invalid_overwrite">Fayl artıq mənsəb qovluğunda mövcuddur</string>
+  <string name="move_file_error">Fayl və ya qovluğun köçürülməsi müddətində səhv baş verdi</string>
+  <string name="forbidden_permissions_move">bu faylı köçürtmək</string>
+  <string name="prefs_category_instant_uploading">Anında yükləmələr</string>
+  <string name="prefs_category_security">Təhlükəsizlik</string>
+  <string name="prefs_instant_video_upload_path_title">Video ünvanını yüklə</string>
+  <string name="download_folder_failed_content">Qovluğun endirilməsinin %1$s hissəsi tamamlana bilməz </string>
+  <string name="subject_token">%1$s paylaşdı \"%2$s\" sizinlə</string>
 </resources>
index 1fd8462..2cd1c81 100644 (file)
   <string name="auth_redirect_non_secure_connection_title">Сигурна връзка е пренасочена по несигурен път.</string>
   <string name="actionbar_logger">Доклади</string>
   <string name="log_send_history_button">Изпрати История</string>
+  <string name="log_send_no_mail_app">Не са намерени журнали за изпращане от приложението. Инсталирайте приложението за електронна поща!</string>
+  <string name="log_send_mail_subject">%1$s Android журнали на приложенията</string>
+  <string name="log_progress_dialog_text">Зареждане на данни...</string>
   <string name="saml_authentication_required_text">Нужна е идентификация</string>
   <string name="saml_authentication_wrong_pass">Грешна парола</string>
   <string name="actionbar_move">Премести</string>
   <string name="forbidden_permissions_move">за да преместиш този файл</string>
   <string name="prefs_category_instant_uploading">Незабавно качване</string>
   <string name="prefs_category_security">Сигурност</string>
-  <string name="shared_subject_header">споделен</string>
+  <string name="prefs_instant_video_upload_path_title">Качване на видео път</string>
+  <string name="download_folder_failed_content">Свалянето на директорията %1$s не може да бъде завършено</string>
 </resources>
index a2861ba..49e04b4 100644 (file)
   <string name="folder_picker_choose_button_text">বেছে নিন</string>
   <string name="move_file_not_found">সরাতে ব্যার্থ হলো। ফাইলটি রয়েছে কিনা দেখুন।</string>
   <string name="prefs_category_security">নিরাপত্তা</string>
-  <string name="shared_subject_header">ভাগাভাগিকৃত</string>
 </resources>
index 9dcb1c6..d0cd67a 100644 (file)
   <string name="saml_authentication_wrong_pass">Contrasenya incorrecta</string>
   <string name="folder_picker_choose_button_text">Escull</string>
   <string name="prefs_category_security">Seguretat</string>
-  <string name="shared_subject_header">compartit</string>
 </resources>
index cca3f49..3429484 100644 (file)
@@ -40,7 +40,7 @@
   <string name="prefs_imprint">Imprint</string>
   <string name="prefs_remember_last_share_location">Zapamatovat umístění sdílení</string>
   <string name="prefs_remember_last_upload_location_summary">Zapamatovat poslední umístění pro nahrání sdílených souborů</string>
-  <string name="recommend_subject">Zkuste %1$s na vašem smartphonu!</string>
+  <string name="recommend_subject">Zkuste %1$s na svém chytrém telefonu!</string>
   <string name="recommend_text">Chtěl bych vás pozvat k používání %1$s na vašem chytrém telefonu!\nKe stažení zde: %2$s</string>
   <string name="auth_check_server">Zkontrolovat server</string>
   <string name="auth_host_url">Adresa serveru https://...</string>
   <string name="auth_oauth_error">Neúspěšné přihlášení</string>
   <string name="auth_oauth_error_access_denied">Přístup zamítnut autorizačním serverem</string>
   <string name="auth_wtf_reenter_URL">Neočekávaný stav; prosím vložte znovu URL adresu serveru</string>
-  <string name="auth_expired_oauth_token_toast">Vaše přihlášení vypršelo. Přihlašte se, prosím, znovu</string>
+  <string name="auth_expired_oauth_token_toast">Vaše přihlášení vypršelo. Přihlaste se prosím znovu</string>
   <string name="auth_expired_basic_auth_toast">Zadejte prosím aktuální heslo</string>
-  <string name="auth_expired_saml_sso_token_toast">Vaše přihlášení vypršelo. Přihlašte se, prosím, znovu</string>
+  <string name="auth_expired_saml_sso_token_toast">Vaše přihlášení vypršelo. Přihlaste se prosím znovu</string>
   <string name="auth_connecting_auth_server">Připojuji se k přihlašovacímu serveru...</string>
   <string name="auth_unsupported_auth_method">Server nepodporuje tuto přihlašovací metodu</string>
   <string name="auth_unsupported_multiaccount">%1$s nepodporuje více účtů</string>
   <string name="auth_fail_get_user_name">Váš server nevrací správné přihlašovací ID, kontaktujte prosím svého správce systému</string>
   <string name="auth_can_not_auth_against_server">Není možné provést ověření  </string>
+  <string name="auth_account_does_not_exist">V zařízení není zatím nastaven účet</string>
   <string name="fd_keep_in_sync">Udržovat soubor aktuální</string>
   <string name="common_rename">Přejmenovat</string>
   <string name="common_remove">Odstranit</string>
@@ -259,6 +260,8 @@ správce systému.</string>
   <string name="share_link_file_error">Při pokusu o sdílení tohoto souboru či složky nastala chyba</string>
   <string name="unshare_link_file_no_exist">Nelze ukončit sdílení. Zkontrolujte prosím že soubor existuje</string>
   <string name="unshare_link_file_error">Při pokusu o zrušení sdílení tohoto souboru či složky nastala chyba</string>
+  <string name="share_link_password_title">Zadejte heslo</string>
+  <string name="share_link_empty_password">Musíte zadat heslo</string>
   <string name="activity_chooser_send_file_title">Odeslat</string>
   <string name="copy_link">Zkopírovat odkaz</string>
   <string name="clipboard_text_copied">Zkopírováno do schránky</string>
@@ -298,7 +301,5 @@ správce systému.</string>
   <string name="prefs_category_security">Zabezpečení</string>
   <string name="prefs_instant_video_upload_path_title">Cesta pro nahrávání videí</string>
   <string name="download_folder_failed_content">Stažení adresáře %1$s nemohlo být dokončeno</string>
-  <string name="shared_subject_header">sdílené</string>
-  <string name="with_you_subject_header">s vámi</string>
-  <string name="subject_token">%1$s %2$s &gt;&gt;%3$s&lt;&lt; %4$s</string>
+  <string name="subject_token">%1$s sdílí \"%2$s\" s vámi</string>
 </resources>
index f4d5761..0e5b458 100644 (file)
   <string name="auth_unsupported_multiaccount">%1$s understøtter ikke multiple konti</string>
   <string name="auth_fail_get_user_name">Din server retunere ikke et korrekt bruger-id. Kontakt venligst din administrator</string>
   <string name="auth_can_not_auth_against_server">Kan ikke autentificere mod denne server</string>
+  <string name="auth_account_does_not_exist">Kontoen findes endnu ikke på enheden</string>
   <string name="fd_keep_in_sync">Hold filen opdateret</string>
   <string name="common_rename">Omdøb</string>
   <string name="common_remove">Fjern</string>
   <string name="share_link_file_error">Der opstod en fejl ved deling af denne fil eller mappe</string>
   <string name="unshare_link_file_no_exist">Kan ikke fjerne deling. Tjek venligst om filen findes.</string>
   <string name="unshare_link_file_error">Der opstod en fejl ved stopning af deling af denne mappe.</string>
+  <string name="share_link_password_title">Angiv et kodeord</string>
+  <string name="share_link_empty_password">Du skal angive et kodeord</string>
   <string name="activity_chooser_send_file_title">Send</string>
   <string name="copy_link">Kopiér link</string>
   <string name="clipboard_text_copied">Kopieret til udklipsholder</string>
   <string name="prefs_category_security">Sikkerhed</string>
   <string name="prefs_instant_video_upload_path_title">Sti til videoupload</string>
   <string name="download_folder_failed_content">Download af %1$s mappe kunne ikke fuldføres</string>
-  <string name="shared_subject_header">delt</string>
-  <string name="with_you_subject_header">med dig</string>
-  <string name="subject_token">%1$s %2$s &gt;&gt;%3$s&lt;&lt; %4$s</string>
+  <string name="subject_token">%1$s delt \"%2$s\" med dig</string>
 </resources>
index eb15d29..0bb8400 100644 (file)
   <string name="auth_no_net_conn_title">Keine Netzwerkverbindung</string>
   <string name="auth_nossl_plain_ok_title">Sichere Verbindung nicht verfügbar.</string>
   <string name="auth_connection_established">Verbindung hergestellt</string>
-  <string name="auth_testing_connection">Verbindungstest …</string>
+  <string name="auth_testing_connection">Verbindungstest…</string>
   <string name="auth_not_configured_title">Fehlerhafte Server Konfiguration</string>
   <string name="auth_account_not_new">Ein Benutzerkonto für den gleichen Benutzer und Server existiert auf diesem Gerät bereits</string>
   <string name="auth_account_not_the_same">Der eingegebene Benutzer passt nicht zu dem Benutzer dieses Benutzerkontos</string>
   <string name="auth_fail_get_user_name">Ihr Server gibt keine richtige Benutzerkennung zurück, bitte kontaktieren Sie einen Administrator
 ⇥</string>
   <string name="auth_can_not_auth_against_server">Die Legitimierung gegenüber dem Server konnte nicht durchgeführt werden</string>
+  <string name="auth_account_does_not_exist">Das Benutzerkonto ist bis jetzt noch nicht auf dem Gerät vorhanden</string>
   <string name="fd_keep_in_sync">Datei aktuell halten</string>
   <string name="common_rename">Umbenennen</string>
   <string name="common_remove">Löschen</string>
   <string name="share_link_file_error">Es ist ein Fehler beim Freigeben der Datei oder des Ordners aufgetreten.</string>
   <string name="unshare_link_file_no_exist">Entfernen der Freigabe nicht möglich. Prüfen Sie, ob die Datei existiert</string>
   <string name="unshare_link_file_error">Es ist ein Fehler beim Entfernen der Freigabe für diese Datei oder den Ordner aufgetreten.</string>
+  <string name="share_link_password_title">Passwort eingeben</string>
+  <string name="share_link_empty_password">Sie müssen ein Passwort eingeben</string>
   <string name="activity_chooser_send_file_title">Senden</string>
   <string name="copy_link">Link kopieren</string>
   <string name="clipboard_text_copied">In die Zwischenablage kopiert</string>
   <string name="prefs_category_security">Sicherheit</string>
   <string name="prefs_instant_video_upload_path_title">Verzeichnis zum Hochladen der Videos</string>
   <string name="download_folder_failed_content">Herunterladen des %1$s - Ordners konnte nicht abgeschlossen werden</string>
-  <string name="shared_subject_header">geteilt</string>
-  <string name="with_you_subject_header">Mit Ihnen</string>
-  <string name="subject_token">%1$s %2$s &gt;&gt;%3$s&lt;&lt; %4$s</string>
+  <string name="subject_token">%1$s hat „%2$s“ mit Ihnen geteilt</string>
 </resources>
index af0e804..3897d60 100644 (file)
@@ -43,7 +43,7 @@
   <string name="recommend_subject">Probiere %1$s auf Deinem Smartphone!</string>
   <string name="recommend_text">Ich möchte Dich zum Benutzen von %1$s auf Deinem Smartphone einladen!\nLade es hier herunter: %2$s</string>
   <string name="auth_check_server">Überprüfe den Server</string>
-  <string name="auth_host_url">Server-Adresse https://…</string>
+  <string name="auth_host_url">Serveradresse https://…</string>
   <string name="auth_username">Benutzername</string>
   <string name="auth_password">Passwort</string>
   <string name="auth_register">Ist %1$s neu für dich?</string>
@@ -61,7 +61,7 @@
   <string name="uploader_info_uploading">Lade hoch</string>
   <string name="file_list_seconds_ago">Gerade eben</string>
   <string name="file_list_empty">Alles leer. Lade etwas hoch!</string>
-  <string name="file_list_loading">Ladevorgang …</string>
+  <string name="file_list_loading">Laden…</string>
   <string name="local_file_list_empty">Es befinden sich keine Dateien in diesem Ordner.</string>
   <string name="file_list_folder">Ordner</string>
   <string name="file_list_folders">Ordner</string>
@@ -75,7 +75,7 @@
   <string name="filedetails_download">Herunterladen</string>
   <string name="filedetails_sync_file">Datei aktualisieren</string>
   <string name="filedetails_renamed_in_upload_msg">Datei wurde wärend des Uploads zu %1$s umbenannt</string>
-  <string name="action_share_file">Link Teilen</string>
+  <string name="action_share_file">Link teilen</string>
   <string name="action_unshare_file">Link nicht mehr freigeben</string>
   <string name="common_yes">Ja</string>
   <string name="common_no">Nein</string>
   <string name="common_cancel">Abbrechen</string>
   <string name="common_save_exit">Speichern &amp; schließen</string>
   <string name="common_error">Fehler</string>
-  <string name="common_loading">Lädt ...</string>
+  <string name="common_loading">Lade…</string>
   <string name="common_error_unknown">Unbekannter Fehler</string>
   <string name="about_title">Über</string>
   <string name="change_password">Passwort ändern</string>
   <string name="delete_account">Account löschen</string>
   <string name="create_account">Account erstellen</string>
-  <string name="upload_chooser_title">Dateien hochladen von...</string>
+  <string name="upload_chooser_title">Dateien hochladen von</string>
   <string name="uploader_info_dirname">Ordnername</string>
-  <string name="uploader_upload_in_progress_ticker">Hochladen...</string>
+  <string name="uploader_upload_in_progress_ticker">Hochladen</string>
   <string name="uploader_upload_in_progress_content">%1$d%% Hochladen %2$s</string>
   <string name="uploader_upload_succeeded_ticker">Hochladen erfolgreich</string>
   <string name="uploader_upload_succeeded_content_single">%1$s wurde(n) erfolgreich hochgeladen</string>
   <string name="uploader_upload_failed_ticker">Hochladen fehlgeschlagen</string>
   <string name="uploader_upload_failed_content_single">Hochladen von  %1$s konnte nicht abgeschlossen werden</string>
   <string name="uploader_upload_failed_credentials_error">Hochladen fehlgeschlagen, Du musst dich nochmals anmelden</string>
-  <string name="downloader_download_in_progress_ticker">Herunterladen...</string>
+  <string name="downloader_download_in_progress_ticker">Herunterladen</string>
   <string name="downloader_download_in_progress_content">%1$d%% Herunterladen %2$s</string>
   <string name="downloader_download_succeeded_ticker">Herunterladen erfolgreich</string>
   <string name="downloader_download_succeeded_content">%1$s wurde erfolgreich heruntergeladen</string>
   <string name="media_rewind_description">Zurückspielen Knopf</string>
   <string name="media_play_pause_description">Play-/Pause Knopf</string>
   <string name="media_forward_description">Vorspulen Knopf</string>
-  <string name="auth_getting_authorization">Autorisierung empfangen...</string>
-  <string name="auth_trying_to_login">Anmeldungsversuch...</string>
+  <string name="auth_getting_authorization">Autorisierung empfangen</string>
+  <string name="auth_trying_to_login">Anmeldeversuch…</string>
   <string name="auth_no_net_conn_title">Keine Netzwerkverbindung</string>
   <string name="auth_nossl_plain_ok_title">Sichere Verbindung nicht verfügbar.</string>
   <string name="auth_connection_established">Verbindung hergestellt</string>
-  <string name="auth_testing_connection">Verbindung testen...</string>
+  <string name="auth_testing_connection">Verbindung testen</string>
   <string name="auth_not_configured_title">Fehlerhafte Server Konfiguration</string>
   <string name="auth_account_not_new">Ein Benutzerkonto für den gleichen Benutzer und Server existiert auf diesem Gerät bereits</string>
   <string name="auth_account_not_the_same">Der eingegebene Benutzer passt nicht zu dem Benutzer dieses Benutzerkontos</string>
   <string name="auth_fail_get_user_name">Dein Server gibt keine korrekte Benutzer-ID zurück, bitte kontaktiere einen Administrator
 </string>
   <string name="auth_can_not_auth_against_server">Die Authentifizierung gegenüber dem Server konnte nicht durchgeführt werden</string>
+  <string name="auth_account_does_not_exist">Das Benutzerkonto ist bis jetzt noch nicht auf dem Gerät vorhanden</string>
   <string name="fd_keep_in_sync">Datei aktuell halten</string>
   <string name="common_rename">Umbenennen</string>
   <string name="common_remove">Löschen</string>
   <string name="wait_a_moment">Bitte warte einen Moment.</string>
   <string name="filedisplay_unexpected_bad_get_content">Ein unerwartetes Problem ist aufgetreten. Bitte versuche, die Datei in einer anderen App zu öffnen</string>
   <string name="filedisplay_no_file_selected">Es wurde keine Datei ausgewählt.</string>
-  <string name="activity_chooser_title">Link senden an ...</string>
+  <string name="activity_chooser_title">Link senden an</string>
   <string name="oauth_check_onoff">Anmelden mit oAuth2</string>
   <string name="oauth_login_connection">Verbinde mit dem oAuth2-Server.</string>
   <string name="ssl_validator_header">Die Identität der Website konnte nicht überprüft werden</string>
   <string name="share_link_file_error">Es ist ein Fehler beim Freigeben der Datei oder des Ordners aufgetreten.</string>
   <string name="unshare_link_file_no_exist">Entfernen der Freigabe nicht möglich. Prüfe, dass die Datei existiert</string>
   <string name="unshare_link_file_error">Es ist ein Fehler beim Entfernen der Freigabe für diese Datei oder den Ordner aufgetreten.</string>
+  <string name="share_link_password_title">Passwort eingeben</string>
+  <string name="share_link_empty_password">Du musst ein Passwort eingeben</string>
   <string name="activity_chooser_send_file_title">Senden</string>
   <string name="copy_link">Link kopieren</string>
   <string name="clipboard_text_copied">In die Zwischenablage kopiert</string>
   <string name="prefs_category_security">Sicherheit</string>
   <string name="prefs_instant_video_upload_path_title">Verzeichnis zum Hochladen der Videos</string>
   <string name="download_folder_failed_content">Herunterladen des %1$s - Ordners konnte nicht abgeschlossen werden</string>
-  <string name="shared_subject_header">geteilt</string>
-  <string name="with_you_subject_header">Mit Dir</string>
-  <string name="subject_token">%1$s %2$s &gt;&gt;%3$s&lt;&lt; %4$s</string>
+  <string name="subject_token">%1$s hat „%2$s“ mit Dir geteilt</string>
 </resources>
index 6faffba..f7ee09f 100644 (file)
   <string name="auth_fail_get_user_name">Ο διακομιστής σας δεν επιστρέφει το σωστό αναγνωριστικό χρήστη, παρακαλώ επικοινωνήστε με ένα διαχειριστή
 ⇥</string>
   <string name="auth_can_not_auth_against_server">Δεν είναι δυνατή η πιστοποίηση με αυτόν το διακομιστή</string>
+  <string name="auth_account_does_not_exist">Ο λογαριασμός δεν υπάρχει στη συσκευή ακόμα.</string>
   <string name="fd_keep_in_sync">Διατήρηση αρχείου σε ενημέρωση</string>
   <string name="common_rename">Μετονομασία</string>
   <string name="common_remove">Αφαίρεση</string>
   <string name="share_link_file_error">Ένα σφάλμα προέκυψε κατά την προσπάθεια διαμοιρασμού αυτού του αρχείου ή φακέλου</string>
   <string name="unshare_link_file_no_exist">Αδύνατη η διακοπή κοινής χρήσης.  Παρακαλώ ελέγξτε αν το αρχείο υπάρχει</string>
   <string name="unshare_link_file_error">Ένα σφάλμα προέκυψε κατά τη διάρκεια ακύρωσης διαμοιρασμού αυτού του αρχείου ή φακέλου</string>
+  <string name="share_link_password_title">Εισάγετε ένα κωδικό πρόσβασης.</string>
+  <string name="share_link_empty_password">Πρέπει να εισάγετε ένα κωδικό πρόσβασης.</string>
   <string name="activity_chooser_send_file_title">Αποστολή</string>
   <string name="copy_link">Αντιγραφή συνδέσμου</string>
   <string name="clipboard_text_copied">Αντιγραφθηκε στο πρόχειρο</string>
   <string name="prefs_category_security">Ασφάλεια</string>
   <string name="prefs_instant_video_upload_path_title">Διαδρομή Μεταφόρτωσης Βίντεο</string>
   <string name="download_folder_failed_content">Η λήψη του φακέλου %1$s δεν ολοκληρώθηκε με επιτυχία.</string>
-  <string name="shared_subject_header">μοιρασμένο </string>
-  <string name="with_you_subject_header">με εσένα</string>
-  <string name="subject_token">%1$s %2$s &gt;&gt;%3$s&lt;&lt; %4$s</string>
+  <string name="subject_token">%1$s μοιράστηκε \"%2$s\" μαζί σας</string>
 </resources>
index 5288af4..d263268 100644 (file)
   <string name="auth_fail_get_user_name">Your server is not returning a correct user id, please contact an administrator
        </string>
   <string name="auth_can_not_auth_against_server">Cannot authenticate against this server</string>
+  <string name="auth_account_does_not_exist">Account does not exist on the device yet</string>
   <string name="fd_keep_in_sync">Keep file up to date</string>
   <string name="common_rename">Rename</string>
   <string name="common_remove">Remove</string>
   <string name="share_link_file_error">An error occurred while trying to share this file or folder</string>
   <string name="unshare_link_file_no_exist">Unable to unshare. Please check whether the file exists</string>
   <string name="unshare_link_file_error">An error occurred while trying to unshare this file or folder</string>
+  <string name="share_link_password_title">Enter a password</string>
+  <string name="share_link_empty_password">You must enter a password</string>
   <string name="activity_chooser_send_file_title">Send</string>
   <string name="copy_link">Copy link</string>
   <string name="clipboard_text_copied">Copied to clipboard</string>
   <string name="prefs_category_security">Security</string>
   <string name="prefs_instant_video_upload_path_title">Upload Video Path</string>
   <string name="download_folder_failed_content">Download of %1$s folder could not be completed</string>
-  <string name="shared_subject_header">shared</string>
-  <string name="with_you_subject_header">with you</string>
-  <string name="subject_token">%1$s %2$s &gt;&gt;%3$s&lt;&lt; %4$s</string>
+  <string name="subject_token">%1$s shared \"%2$s\" with you</string>
 </resources>
index 4c604f0..faf4525 100644 (file)
   <string name="saml_authentication_wrong_pass">Malĝusta pasvorto</string>
   <string name="folder_picker_choose_button_text">Elekti</string>
   <string name="prefs_category_security">Sekuro</string>
-  <string name="shared_subject_header">kunhavigita</string>
 </resources>
index 6100a40..dca9e4a 100644 (file)
   <string name="actionbar_settings">Configuración</string>
   <string name="actionbar_see_details">Detalles</string>
   <string name="actionbar_send_file">Mandar</string>
+  <string name="actionbar_sort">Orden</string>
+  <string name="actionbar_sort_title">Ordenar por</string>
+  <string-array name="actionbar_sortby">
+    <item>A-Z</item>
+    <item>Nuevos - Viejos</item>
+  </string-array>
   <!--TODO re-enable when server-side folder size calculation is available   
        <item>Biggest - Smallest</item>-->
   <string name="prefs_category_general">General</string>
   <string name="prefs_recommend">Recomendar a un amigo</string>
   <string name="prefs_feedback">Sugerencias</string>
   <string name="prefs_imprint">Imprint</string>
+  <string name="prefs_remember_last_share_location">Recordar compartir ubicación </string>
+  <string name="prefs_remember_last_upload_location_summary">Recordar la ultima ubicación compartida de subida</string>
   <string name="recommend_subject">¡Intento %1$s en tu teléfono inteligente!</string>
+  <string name="recommend_text">Quiero invitarte a usar %1$s en tu teléfono inteligente!\nDescárgalo aquí: %2$s</string>
   <string name="auth_check_server">Verificar Servidor</string>
   <string name="auth_host_url">Dirección del servidor https://...</string>
   <string name="auth_username">Nombre de usuario</string>
   <string name="conflict_dont_upload">No subir</string>
   <string name="preview_image_description">Previsualización de imagen</string>
   <string name="preview_image_error_unknown_format">Esta imagen no puede ser mostrada</string>
+  <string name="error__upload__local_file_not_copied">%1$s no pudo ser copiado a la carpeta local %2$s </string>
+  <string name="prefs_instant_upload_path_title">Dirección de subida</string>
+  <string name="share_link_no_support_share_api">Lo sentimos, compartir no esta activado en su servidor. Por favor contacte a su
+⇥⇥administrator.</string>
+  <string name="share_link_file_no_exist">Imposible compartir. Por favor revise si el archivo existe</string>
+  <string name="share_link_file_error">Un error ocurrió cuando se intentaba compartir el archivo o carpeta</string>
+  <string name="unshare_link_file_no_exist">Imposible dejar de compartir. Por favor revise si los archivos existen</string>
+  <string name="unshare_link_file_error">Un error ocurrió cuando se intentaba dejar de compartir el archivo o carpeta</string>
   <string name="activity_chooser_send_file_title">Mandar</string>
+  <string name="copy_link">Copiar dirección url</string>
   <string name="clipboard_text_copied">Copiado al portapapeles</string>
+  <string name="error_cant_bind_to_operations_service">Error critico: no se puede realizar operaciones</string>
+  <string name="network_error_socket_exception">Un error ocurrió mientras se conectaba con el Servidor.</string>
+  <string name="network_error_socket_timeout_exception">Un error ocurrió mientras se conectaba con el Servidor. La operación no se realizó </string>
+  <string name="network_error_connect_timeout_exception">Un error ocurrió esperando al Servidor, la operación no se realizó</string>
+  <string name="network_host_not_available">Operación no completada, Servidor no disponible.</string>
   <string name="empty"></string>
+  <string name="forbidden_permissions">Tu no tienes permiso %s</string>
+  <string name="forbidden_permissions_rename">para renombrar este archivo</string>
+  <string name="forbidden_permissions_delete">para borrar este archivo</string>
+  <string name="share_link_forbidden_permissions">para compartir este archivo</string>
+  <string name="unshare_link_forbidden_permissions">para dejar de compartir este archivo</string>
+  <string name="forbidden_permissions_create">para crear el archivo</string>
+  <string name="uploader_upload_forbidden_permissions">para subir en esta carpeta</string>
+  <string name="downloader_download_file_not_found">El archivo no esta mas disponible en este Servidor</string>
   <string name="prefs_category_accounts">Cuentas</string>
+  <string name="prefs_add_account">Añadir cuenta</string>
+  <string name="auth_redirect_non_secure_connection_title">Conexión segura redireccionada a una ruta insegura.</string>
+  <string name="actionbar_logger">Registro</string>
+  <string name="log_send_history_button">Enviar Historial</string>
+  <string name="log_send_no_mail_app">Aplicación para enviar registros no encontrada. Instale una aplicación de correo!</string>
+  <string name="log_send_mail_subject">%1$s Registros de la aplicación Android</string>
+  <string name="log_progress_dialog_text">Cargando datos...</string>
   <string name="saml_authentication_required_text">Autentificación requerida</string>
   <string name="saml_authentication_wrong_pass">Clave incorrecta</string>
+  <string name="actionbar_move">Mover</string>
+  <string name="file_list_empty_moving">Nada aquí. Puedes agregar una carpeta!</string>
   <string name="folder_picker_choose_button_text">Elegir</string>
+  <string name="move_file_not_found">Imposible mover. Por favor revisa si el archivo existe</string>
+  <string name="move_file_invalid_overwrite">El archivo ya existe en la carpeta destino</string>
+  <string name="move_file_error">Un error ocurrió intentando mover el archivo o carpeta</string>
+  <string name="forbidden_permissions_move">para mover este archivo</string>
+  <string name="prefs_category_instant_uploading">Subida Instantánea </string>
   <string name="prefs_category_security">Seguridad</string>
-  <string name="shared_subject_header">compartido</string>
+  <string name="prefs_instant_video_upload_path_title">Dirección de subida del video</string>
+  <string name="download_folder_failed_content">La descarga de la carpeta %1$s no pudo ser completada</string>
 </resources>
index 69623e1..26dde5f 100644 (file)
@@ -1,6 +1,8 @@
 <?xml version='1.0' encoding='UTF-8'?>
 <resources>
+  <string name="actionbar_upload_files">Archivos</string>
   <!--TODO re-enable when server-side folder size calculation is available   
        <item>Biggest - Smallest</item>-->
+  <string name="sync_string_files">Archivos</string>
   <string name="empty"></string>
 </resources>
index 5758463..a760bfe 100644 (file)
   <string name="saml_authentication_wrong_pass">Contraseña incorrecta</string>
   <string name="folder_picker_choose_button_text">Seleccionar</string>
   <string name="prefs_category_security">Seguridad</string>
-  <string name="shared_subject_header">compartido</string>
 </resources>
index a3d335f..47dff01 100644 (file)
@@ -7,7 +7,7 @@
   <string name="actionbar_upload_from_apps">Contenido de otras aplicaciones</string>
   <string name="actionbar_upload_files">Archivos</string>
   <string name="actionbar_open_with">Abrir con</string>
-  <string name="actionbar_mkdir">Nueva Carpeta</string>
+  <string name="actionbar_mkdir">Nueva carpeta</string>
   <string name="actionbar_settings">Configuración</string>
   <string name="actionbar_see_details">Detalles</string>
   <string name="actionbar_send_file">Enviar</string>
@@ -40,7 +40,7 @@
   <string name="prefs_imprint">pie de imprenta</string>
   <string name="prefs_remember_last_share_location">Recordar la ubicación de los archivos compartidos</string>
   <string name="prefs_remember_last_upload_location_summary">Recordar la ubicación de los últimos archivos compartidos subidos</string>
-  <string name="recommend_subject">Prueba  %1$s en tu smarthphone!</string>
+  <string name="recommend_subject">¡Prueba  %1$s en su smarthphone!</string>
   <string name="recommend_text">¡Quiero invitarle a usar %1$s en su smartphone!\nDescárguelo aquí: %2$s</string>
   <string name="auth_check_server">Compruebe el servidor.</string>
   <string name="auth_host_url">Dirección del servidor https://…</string>
@@ -52,7 +52,7 @@
   <string name="uploader_btn_upload_text">Subir</string>
   <string name="uploader_top_message">Escoger carpeta de carga:</string>
   <string name="uploader_wrn_no_account_title">No se encontró la cuenta</string>
-  <string name="uploader_wrn_no_account_text">No hay cuentas de %1$s en tu dispositivo. Por favor configura una cuenta primero.</string>
+  <string name="uploader_wrn_no_account_text">No hay cuentas de %1$s en su dispositivo. Por favor, configure una cuenta primero.</string>
   <string name="uploader_wrn_no_account_setup_btn_text">Configuración</string>
   <string name="uploader_wrn_no_account_quit_btn_text">Salir</string>
   <string name="uploader_wrn_no_content_title">No hay contenido para subir</string>
@@ -85,7 +85,7 @@
   <string name="common_cancel">Cancelar</string>
   <string name="common_save_exit">Guardar &amp; Salir</string>
   <string name="common_error">Error</string>
-  <string name="common_loading">Cargando ...</string>
+  <string name="common_loading">Cargando...</string>
   <string name="common_error_unknown">Error desconocido</string>
   <string name="about_title">Acerca de</string>
   <string name="change_password">Cambiar contraseña</string>
   <string name="uploader_upload_failed_ticker">Error en la subida</string>
   <string name="uploader_upload_failed_content_single">La subida de %1$s no se pudo completar</string>
   <string name="uploader_upload_failed_credentials_error">La carga falló, necesita volver a iniciar sesión</string>
-  <string name="downloader_download_in_progress_ticker">Descargando ...</string>
+  <string name="downloader_download_in_progress_ticker">Descargando...</string>
   <string name="downloader_download_in_progress_content">%1$d%% Descargado de %2$s</string>
   <string name="downloader_download_succeeded_ticker">Descarga completa</string>
   <string name="downloader_download_succeeded_content">%1$s se ha descargado con éxito</string>
   <string name="downloader_download_failed_content">La descarga de %1$s no se pudo completar</string>
   <string name="downloader_not_downloaded_yet">No descargado</string>
   <string name="downloader_download_failed_credentials_error">Descarga fallida, necesita reinicar la sesión</string>
-  <string name="common_choose_account">Elige una cuenta</string>
+  <string name="common_choose_account">Elija una cuenta</string>
   <string name="sync_fail_ticker">Falló la sincronización</string>
   <string name="sync_fail_ticker_unauthorized">La sincronización falló, debe reiniciar la sesión</string>
   <string name="sync_fail_content">La sincronización de %1$s s no se pudo completar</string>
   <string name="foreign_files_local_text">Local: %1$s</string>
   <string name="foreign_files_remote_text">Remoto: %1$s</string>
   <string name="upload_query_move_foreign_files">No hay suficiente espacio para copiar los archivos seleccionados a la carpeta %1$s. ¿Desea moverlos en vez de copiarlos?</string>
-  <string name="pincode_enter_pin_code">Por favor, inserta tu PIN de aplicación</string>
+  <string name="pincode_enter_pin_code">Por favor, inserte su PIN de aplicación</string>
   <string name="pincode_configure_your_pin">Introduzca un PIN para la aplicación</string>
   <string name="pincode_configure_your_pin_explanation">Se solicitará el PIN cada vez que se inicie la aplicación</string>
   <string name="pincode_reenter_your_pincode">Repita el PIN para la aplicación, por favor</string>
   <string name="media_event_done">%1$s reproducción finalizada</string>
   <string name="media_err_nothing_to_play">No se encontró el archivo multimedia</string>
   <string name="media_err_no_account">No se ha proporcionado cuenta</string>
-  <string name="media_err_not_in_owncloud">El archivo no esta en una cuenta valida </string>
-  <string name="media_err_unsupported">Codec No Soportado</string>
+  <string name="media_err_not_in_owncloud">El archivo no está en una cuenta válida </string>
+  <string name="media_err_unsupported">Codec no soportado</string>
   <string name="media_err_io">El archivo de medios no pudo ser leído </string>
   <string name="media_err_malformed">Archivo no codificado correctamente</string>
   <string name="media_err_timeout">Tiempo de espera agotado en el intento de reproducción</string>
   <string name="media_err_unknown">El archivo de medios no se puede reproducir con el reproductor de medios por defecto </string>
   <string name="media_err_security_ex">Error de seguridad al intentar reproducir %1$s</string>
   <string name="media_err_io_ex">Error de entrada al intentar reproducir %1$s</string>
-  <string name="media_err_unexpected">Error inesperado intentando reproducir %1$s</string>
-  <string name="media_rewind_description">Botón Rebobinado</string>
+  <string name="media_err_unexpected">Error inesperado al intentar reproducir %1$s</string>
+  <string name="media_rewind_description">Botón de rebobinado</string>
   <string name="media_play_pause_description">Botón de reproducción o pausa </string>
   <string name="media_forward_description">Botón avance rápido</string>
   <string name="auth_getting_authorization">Consiguiendo autorización...</string>
   <string name="auth_bad_oc_version_title">No se reconoce  la versión del servidor </string>
   <string name="auth_wrong_connection_title">No se ha podido establecer la conexión</string>
   <string name="auth_secure_connection">Conexión segura establecida</string>
-  <string name="auth_unauthorized">Nombre de usuario o contraseña incorrecta</string>
+  <string name="auth_unauthorized">Nombre de usuario o contraseña incorrectos</string>
   <string name="auth_oauth_error">Autorización no satisfactoria</string>
   <string name="auth_oauth_error_access_denied">Acceso denegado por servidor de autorización</string>
   <string name="auth_wtf_reenter_URL">Estado inesperado; por favor, introduzca la URL del servidor de nuevo</string>
   <string name="auth_fail_get_user_name">Su servidor no está retornando una identificación de usuario correcta; contacte a un administrador
        </string>
   <string name="auth_can_not_auth_against_server">No puede autenticarse en este servidor.</string>
+  <string name="auth_account_does_not_exist">Aún no existe la cuenta en el dispositivo</string>
   <string name="fd_keep_in_sync">Mantener el archivo actualizado</string>
   <string name="common_rename">Renombrar</string>
   <string name="common_remove">Borrar</string>
   <string name="filename_forbidden_characters">Carácteres ilegales: / \\ &lt; &gt; : \" | ? *</string>
   <string name="filename_empty">El nombre de archivo no puede estar vacío</string>
   <string name="wait_a_moment">Espere un momento</string>
-  <string name="filedisplay_unexpected_bad_get_content">Problema inesperado; por favor, prueba otra app para seleccionar el archivo</string>
+  <string name="filedisplay_unexpected_bad_get_content">Problema inesperado; por favor, pruebe otra app para seleccionar el archivo</string>
   <string name="filedisplay_no_file_selected">No hay ficheros seleccionados.</string>
   <string name="activity_chooser_title">Enviar enlace a...</string>
   <string name="oauth_check_onoff">Ingresar con oAuth2</string>
   <string name="ssl_validator_reason_cert_expired">- El certificado del servidor expiró</string>
   <string name="ssl_validator_reason_cert_not_yet_valid">- El certificado del servidor es de una fecha que aún no ha llegado</string>
   <string name="ssl_validator_reason_hostname_not_verified">- La URL no coincide con el nombre de dominio del certificado</string>
-  <string name="ssl_validator_question">¿Confías de todas formas en este certificado?</string>
+  <string name="ssl_validator_question">¿Confía de todas formas en este certificado?</string>
   <string name="ssl_validator_not_saved">El certificado no pudo ser guardado</string>
   <string name="ssl_validator_btn_details_see">Detalles</string>
   <string name="ssl_validator_btn_details_hide">Ocultar</string>
   <string name="share_link_file_error">Ocurrió un error al tratar de compartir este archivo o carpeta</string>
   <string name="unshare_link_file_no_exist">No se puede dejar de compartir. Revise si el archivo existe</string>
   <string name="unshare_link_file_error">Ocurrió un error al tratar de ya no compartir este archivo o carpeta</string>
+  <string name="share_link_password_title">Introduzca una contraseña</string>
+  <string name="share_link_empty_password">Debe introducir una contraseña</string>
   <string name="activity_chooser_send_file_title">Enviar</string>
   <string name="copy_link">Copiar enlace</string>
   <string name="clipboard_text_copied">Copiado al portapapeles</string>
   <string name="saml_authentication_wrong_pass">Contraseña incorrecta</string>
   <string name="actionbar_move">Mover</string>
   <string name="file_list_empty_moving">Aquí no hay nada. ¡Puede agregar una carpeta!</string>
-  <string name="folder_picker_choose_button_text">Seleccionar</string>
+  <string name="folder_picker_choose_button_text">Elegir</string>
   <string name="move_file_not_found">No se puede mover. Revise si el archivo existe</string>
   <string name="move_file_invalid_into_descendent">No se puede mover una carpeta dentro de una de SUS subcarpetas.</string>
   <string name="move_file_invalid_overwrite">El archivo ya existe en la carpeta de destino</string>
   <string name="prefs_category_instant_uploading">Subidas instantáneas</string>
   <string name="prefs_category_security">Seguridad</string>
   <string name="prefs_instant_video_upload_path_title">Guardar videos subidos en la carpeta:</string>
-  <string name="download_folder_failed_content">Descarga de la carpeta %1$s no ha podido ser completada</string>
-  <string name="shared_subject_header">compartido</string>
-  <string name="with_you_subject_header">contigo</string>
-  <string name="subject_token">%1$s %2$s &gt;&gt;%3$s&lt;&lt; %4$s</string>
+  <string name="download_folder_failed_content">La descarga de la carpeta %1$s no ha podido ser completada</string>
+  <string name="subject_token">%1$s compartió \"%2$s\" contigo</string>
 </resources>
index 84636cc..e7ac96b 100644 (file)
@@ -298,5 +298,4 @@ Allpool on loend kohalikest failidest ning serveris asuvatest failidest %5$s, mi
   <string name="forbidden_permissions_move">selle faili liigutamiseks</string>
   <string name="prefs_category_instant_uploading">Kohesed üleslaadimised</string>
   <string name="prefs_category_security">Turvalisus</string>
-  <string name="shared_subject_header">jagatud</string>
 </resources>
index 6b96f28..0bca462 100644 (file)
@@ -12,6 +12,7 @@
   <string name="actionbar_see_details">Xehetasunak</string>
   <string name="actionbar_send_file">Bidali</string>
   <string name="actionbar_sort">Ordenatu</string>
+  <string name="actionbar_sort_title">Ordenatu honen arabera</string>
   <string-array name="actionbar_sortby">
     <item>A-Z</item>
     <item>Berrienak - Zaharrenak</item>
@@ -38,6 +39,7 @@
   <string name="prefs_feedback">Oharrak</string>
   <string name="prefs_imprint">Imprint</string>
   <string name="recommend_subject">Probatu %1$s zure telefono adimentsuan!</string>
+  <string name="recommend_text">Nik %1$s zure telefono adimentsuan erabitzera gonbidatu nahi zaitut!\nDeskargatu hemen: %2$s</string>
   <string name="auth_check_server">Egiaztatu zerbitzaria</string>
   <string name="auth_host_url">Zerbitzariaren helbidea https://</string>
   <string name="auth_username">Erabiltzaile izena</string>
   <string name="sync_fail_in_favourites_content">%1$d fitxategien edukiak ezin dira sinkronizatu (%2$d gatazka)</string>
   <string name="sync_foreign_files_forgotten_ticker">Bertako fitxategi batzuk ahaztu dira</string>
   <string name="sync_foreign_files_forgotten_content">%2$s karpetako %1$d fitxategi ezin dira dira kopiatu</string>
+  <string name="sync_foreign_files_forgotten_explanation">1.3.16 bertsioan, gailu honetatik igotzen diren fitxategiak bertako %1$s karpetara mugitzen dira datu galera ekiditeko fitxategi bat kontu ezberdinekin sinkronizatzen denean.\n\n Aldaketa hau dela eta, programa honen aurreko bertsioetan igotako fitxategi guztiak %2$s karpetara kopiatu dira. Hala ere, errore batek hau burutzea ekidin du kontuaren sinkronizazioa egiten ari zen bitartean. Orain fitxategiak dauden bezala utz ditzakezu eta %3$s rako lotura ezabatu, edo fitxategiak %1$s karpetara mugi ditzakezu eta %4$srako lotura mantendu.\n\nBehean bertako fitxategien zerrenda eta %5$s era lotuta zeuden urruneko fitxategiena.</string>
   <string name="sync_current_folder_was_removed">%1$s karpeta dagoeneko ez da existitzen</string>
   <string name="foreign_files_move">Mugitu denak</string>
   <string name="foreign_files_success">Fitxategi guztiak mugitu dira</string>
@@ -250,7 +253,9 @@ Mesedez, baimendu berriz</string>
   <string name="error__upload__local_file_not_copied">%1$s ezin da %2$s karpeta lokalera kopiatu</string>
   <string name="prefs_instant_upload_path_title">Igotzetarako Bidea</string>
   <string name="share_link_no_support_share_api">Sentitzen dut, partekatzea ez dago zure zerbitzarian gaituta. Mesedez jarri harremanetan zure administratzailearekin.</string>
+  <string name="share_link_file_no_exist">Ezin izan da partekatu. Mesedez egiaztatu fitxategia existitzen dela</string>
   <string name="share_link_file_error">Errore bat egon da fitxategaia edo karpeta partekatzerakoan</string>
+  <string name="unshare_link_file_no_exist">Ezin izan da partekatzea desegin. Mesedez egiaztatu fitxategia existitzen dela</string>
   <string name="unshare_link_file_error">Errore bat egon da fitxategaia edo karpeta partekatzeari uzterakoan</string>
   <string name="activity_chooser_send_file_title">Bidali</string>
   <string name="copy_link">Lotura kopiatu</string>
@@ -271,15 +276,23 @@ Mesedez, baimendu berriz</string>
   <string name="downloader_download_file_not_found">Fitxategia jadanik ez dago eskuragarri zerbitzarian</string>
   <string name="prefs_category_accounts">Kontuak</string>
   <string name="prefs_add_account">Gehitu kontua</string>
+  <string name="auth_redirect_non_secure_connection_title">Konexio segurua birbideratu da segurua ez den bide batera.</string>
+  <string name="actionbar_logger">Egunkariak</string>
+  <string name="log_send_history_button">Bidali Historia</string>
+  <string name="log_send_no_mail_app">Egunkariak bidaltzeko aplikaziorik ez da aurkitu. Instalatu posta aplikazioa!</string>
   <string name="log_send_mail_subject">%1$s Android aplikazioaren egunerokoak</string>
   <string name="log_progress_dialog_text">Datuak kargatzen...</string>
   <string name="saml_authentication_required_text">Autentikazioa beharrezkoa</string>
   <string name="saml_authentication_wrong_pass">Pasahitz okerra</string>
   <string name="actionbar_move">Mugitu</string>
+  <string name="file_list_empty_moving">Hemen ez dago ezer. Karpeta bat gehi dezakezu!</string>
   <string name="folder_picker_choose_button_text">Aukeratu</string>
+  <string name="move_file_not_found">Ezin izan da mugitu. Mesedez egiaztatu fitxategia existitzen dela</string>
+  <string name="move_file_invalid_overwrite">Fitxategia dagoeneko existitzen da helburuko karpetan</string>
+  <string name="move_file_error">Errore bat gertatu da fitxategi edo karpeta hau mugitzen saiatzerakoan</string>
+  <string name="forbidden_permissions_move">fitxategi hau mugitzeko</string>
   <string name="prefs_category_instant_uploading">Berehalako Igoerak</string>
   <string name="prefs_category_security">Segurtasuna</string>
-  <string name="shared_subject_header">konpartitua</string>
-  <string name="with_you_subject_header">zurekin</string>
-  <string name="subject_token">%1$s %2$s &gt;&gt;%3$s&lt;&lt; %4$s</string>
+  <string name="prefs_instant_video_upload_path_title">Bideo Igoera Bidea</string>
+  <string name="download_folder_failed_content">%1$s karpetaren deskarga ezin izan da burutu</string>
 </resources>
index 142e71b..0140c07 100644 (file)
   <string name="saml_authentication_wrong_pass">رمز عبور اشتباه است</string>
   <string name="folder_picker_choose_button_text">انتخاب کردن</string>
   <string name="prefs_category_security">امنیت</string>
-  <string name="shared_subject_header">اشتراک گذاشته شده</string>
 </resources>
index 5273257..35b677a 100644 (file)
   <string name="auth_unsupported_auth_method">Palvelin ei tue tätä tunnistautumistapaa</string>
   <string name="auth_unsupported_multiaccount">%1$s ei tue useita tilejä</string>
   <string name="auth_can_not_auth_against_server">Tunnistautuminen palvelinta vastaan ei onnistu</string>
+  <string name="auth_account_does_not_exist">Tiliä ei ole olemassa vielä laitteella</string>
   <string name="fd_keep_in_sync">Pidä tiedosto ajan tasalla</string>
   <string name="common_rename">Nimeä uudelleen</string>
   <string name="common_remove">Poista</string>
   <string name="share_link_no_support_share_api">Jakaminen ei ole käytössä palvelimellasi. Ota yhteys
                ylläpitäjään.</string>
   <string name="share_link_file_error">Virhe tiedoston tai kansion jakamista yrittäessä</string>
+  <string name="share_link_password_title">Anna salasana</string>
+  <string name="share_link_empty_password">Salasana on pakko antaa</string>
   <string name="activity_chooser_send_file_title">Lähetä</string>
   <string name="copy_link">Kopioi linkki</string>
   <string name="clipboard_text_copied">Kopioitu leikepöydälle</string>
   <string name="move_file_error">Tämän tiedoston tai kansion siirtoa yrittäessä tapahtui virhe</string>
   <string name="prefs_category_instant_uploading">Välittömät lähetykset</string>
   <string name="prefs_category_security">Tietoturva</string>
-  <string name="shared_subject_header">jaettu</string>
-  <string name="with_you_subject_header">kanssasi</string>
+  <string name="subject_token">%1$s jakoi kohteen \"%2$s\" kanssasi</string>
 </resources>
index 3b3b347..4f531a7 100644 (file)
@@ -25,9 +25,9 @@
   <string name="prefs_manage_accounts">Gestion des comptes</string>
   <string name="prefs_pincode">Code de sécurité</string>
   <string name="prefs_pincode_summary">Protéger l\'accès à l\'application</string>
-  <string name="prefs_instant_upload">Envoi instantané des photos</string>
+  <string name="prefs_instant_upload">Téléversement immédiat des photos</string>
   <string name="prefs_instant_upload_summary">Téléverser immédiatement les photos prises par la caméra</string>
-  <string name="prefs_instant_video_upload">Envoi instantané des vidéos</string>
+  <string name="prefs_instant_video_upload">Téléversement immédiat des vidéos</string>
   <string name="prefs_instant_video_upload_summary">Téléverser immédiatement les vidéos prises par la caméra</string>
   <string name="prefs_log_title">Activer les logs</string>
   <string name="prefs_log_summary">Utilisé pour enregistrer les problèmes dans les logs</string>
@@ -39,7 +39,7 @@
   <string name="prefs_feedback">Commentaires</string>
   <string name="prefs_imprint">Empreinte</string>
   <string name="prefs_remember_last_share_location">Mémoriser l\'emplacement de partage</string>
-  <string name="prefs_remember_last_upload_location_summary">Mémoriser le dernier emplacement d\'upload</string>
+  <string name="prefs_remember_last_upload_location_summary">Mémoriser le dernier emplacement de téléversement</string>
   <string name="recommend_subject">Essayez %1$s sur votre smartphone !</string>
   <string name="recommend_text">J\'aimerais vous inviter à utiliser %1$s sur votre smartphone !
 Téléchargez-le ici : %2$s</string>
@@ -54,12 +54,12 @@ Téléchargez-le ici : %2$s</string>
   <string name="uploader_top_message">Sélectionner le dossier d\'envoi :</string>
   <string name="uploader_wrn_no_account_title">Aucun compte n\'a été trouvé</string>
   <string name="uploader_wrn_no_account_text">Aucun compte %1$s n\'a été trouvé. Veuillez commencer par en configurer un.</string>
-  <string name="uploader_wrn_no_account_setup_btn_text">Paramètres</string>
+  <string name="uploader_wrn_no_account_setup_btn_text">Configuration</string>
   <string name="uploader_wrn_no_account_quit_btn_text">Quitter</string>
   <string name="uploader_wrn_no_content_title">Rien à envoyer</string>
   <string name="uploader_wrn_no_content_text">Aucun contenu reçu. Rien à envoyer.</string>
   <string name="uploader_error_forbidden_content">%1$s n\'est pas autorisé à accéder au contenu partagé</string>
-  <string name="uploader_info_uploading">Téléversement</string>
+  <string name="uploader_info_uploading">Téléversement...</string>
   <string name="file_list_seconds_ago">il y a quelques secondes</string>
   <string name="file_list_empty">Il n\'y a rien ici ! Envoyez donc quelque chose :)</string>
   <string name="file_list_loading">Chargement…</string>
@@ -68,7 +68,7 @@ Téléchargez-le ici : %2$s</string>
   <string name="file_list_folders">dossiers</string>
   <string name="file_list_file">fichier</string>
   <string name="file_list_files">fichiers</string>
-  <string name="filedetails_select_file">Effleurez un fichier pour afficher les informations complémentaires</string>
+  <string name="filedetails_select_file">Effleurez un fichier pour afficher les informations complémentaires.</string>
   <string name="filedetails_size">Taille :</string>
   <string name="filedetails_type">Type :</string>
   <string name="filedetails_created">Créé le :</string>
@@ -82,7 +82,7 @@ Téléchargez-le ici : %2$s</string>
   <string name="common_no">Non</string>
   <string name="common_ok">OK</string>
   <string name="common_cancel_download">Annuler le téléchargement</string>
-  <string name="common_cancel_upload">Annuler l\'envoi</string>
+  <string name="common_cancel_upload">Annuler le téléversement</string>
   <string name="common_cancel">Annuler</string>
   <string name="common_save_exit">Sauvegarder &amp; Quitter</string>
   <string name="common_error">Erreur</string>
@@ -90,14 +90,14 @@ Téléchargez-le ici : %2$s</string>
   <string name="common_error_unknown">Erreur inconnue </string>
   <string name="about_title">À propos de</string>
   <string name="change_password">Changer de mot de passe</string>
-  <string name="delete_account">Effacer ce compte</string>
+  <string name="delete_account">Supprimer ce compte</string>
   <string name="create_account">Créer un compte</string>
   <string name="upload_chooser_title">Téléverser un fichier depuis…</string>
   <string name="uploader_info_dirname">Nom du dossier</string>
   <string name="uploader_upload_in_progress_ticker">Téléversement…</string>
   <string name="uploader_upload_in_progress_content">Envoi du fichier %2$s : %1$d%% effectués</string>
   <string name="uploader_upload_succeeded_ticker">Téléversement réussi</string>
-  <string name="uploader_upload_succeeded_content_single">Le fichier %1$s a été envoyé avec succès</string>
+  <string name="uploader_upload_succeeded_content_single">Le fichier %1$s a été téléversé avec succès</string>
   <string name="uploader_upload_failed_ticker">Échec de l\'envoi</string>
   <string name="uploader_upload_failed_content_single">L\'envoi de %1$s a échoué</string>
   <string name="uploader_upload_failed_credentials_error">Le téléversement a échoué, vous devez vous connecter à nouveau</string>
@@ -111,7 +111,7 @@ Téléchargez-le ici : %2$s</string>
   <string name="downloader_download_failed_credentials_error">Le téléchargement a échoué, vous devez vous connecter à nouveau</string>
   <string name="common_choose_account">Choisissez un compte</string>
   <string name="sync_fail_ticker">La synchronisation a échoué</string>
-  <string name="sync_fail_ticker_unauthorized">Échec de la synchronisation, vous devez vous reconnecter à nouveau</string>
+  <string name="sync_fail_ticker_unauthorized">Échec de la synchronisation, vous devez vous reconnecter</string>
   <string name="sync_fail_content">La synchronisation de %1$s n\'a pu être terminée</string>
   <string name="sync_fail_content_unauthorized">Mot de passe non valide pour %1$s</string>
   <string name="sync_conflicts_in_favourites_ticker">Des conflits ont été trouvés</string>
@@ -120,9 +120,9 @@ Téléchargez-le ici : %2$s</string>
   <string name="sync_fail_in_favourites_content">Le contenu de %1$d fichiers n\'a pu être synchronisé (%2$d conflits)</string>
   <string name="sync_foreign_files_forgotten_ticker">Certains fichiers locaux ont été oubliés</string>
   <string name="sync_foreign_files_forgotten_content">%1$d fichiers du dossier %2$s n\'ont pas pu être copiés dans</string>
-  <string name="sync_foreign_files_forgotten_explanation">Depuis la version 1.3.16, les fichiers envoyé depuis ce périphérique sont copiés dans le dossier local %1$s pour éviter une perte de données lorsqu\'un même fichier est synchronisé avec plusieurs comptes.
+  <string name="sync_foreign_files_forgotten_explanation">Depuis la version 1.3.16, les fichiers envoyés depuis ce périphérique sont copiés dans le dossier local %1$s pour éviter une perte de données lorsqu\'un même fichier est synchronisé avec plusieurs comptes.
 
-En raison de cette modification, tous les fichiers envoyés avec des versions antérieures de cette application ont été copiés dans le dossier %2$s. Cependant une erreur a empêché l\'achèvement de cette opération pendant la synchronisation du compte. Vous pouvez soit laisser les fichiers tels quels et supprimer le lien vers %3$s, soit déplacer les fichiers dans le dossier %1$s et garder le lien vers %4$s.
+En raison de cette modification, tous les fichiers envoyés avec des versions antérieures de cette application ont été copiés dans le dossier %2$s. Cependant, une erreur a empêché l\'achèvement de cette opération pendant la synchronisation du compte. Vous pouvez soit laisser les fichiers tels quels et supprimer le lien vers %3$s, soit déplacer les fichiers dans le dossier %1$s et garder le lien vers %4$s.
 
 Ci-dessous la liste des fichiers locaux, et les fichiers distants dans %5$s auxquels ils étaient liés.</string>
   <string name="sync_current_folder_was_removed">Le dossier %1$s n\'existe plus</string>
@@ -131,11 +131,11 @@ Ci-dessous la liste des fichiers locaux, et les fichiers distants dans %5$s auxq
   <string name="foreign_files_fail">Certains fichiers n\'ont pu être déplacés</string>
   <string name="foreign_files_local_text">Local : %1$s</string>
   <string name="foreign_files_remote_text">Distant : %1$s</string>
-  <string name="upload_query_move_foreign_files">Il n\'y a pas assez de place disponible pour copier les fichiers sélectionnés dans le dossier %1$s. Voulez-vous quand même les déplacer ?</string>
+  <string name="upload_query_move_foreign_files">Il n\'y a pas assez de place disponible pour copier les fichiers sélectionnés dans le dossier %1$s. Voulez-vous les déplacer à la place ?</string>
   <string name="pincode_enter_pin_code">Veuillez saisir votre code de sécurité</string>
   <string name="pincode_configure_your_pin">Veuillez saisir votre code de sécurité </string>
-  <string name="pincode_configure_your_pin_explanation">Le code PIN vous sera demandé à chaque lancement de l\'application</string>
-  <string name="pincode_reenter_your_pincode">Veuillez saisir à nouveau votre code de sécurité</string>
+  <string name="pincode_configure_your_pin_explanation">Le code de sécurité vous sera demandé à chaque lancement de l\'application</string>
+  <string name="pincode_reenter_your_pincode">Veuillez saisir de nouveau votre code de sécurité</string>
   <string name="pincode_remove_your_pincode">Retirer le code de sécurité</string>
   <string name="pincode_mismatch">Les deux codes saisis ne concordent pas</string>
   <string name="pincode_wrong">Code de sécurité incorrect</string>
@@ -167,12 +167,12 @@ Ci-dessous la liste des fichiers locaux, et les fichiers distants dans %5$s auxq
   <string name="auth_connection_established">Connexion établie</string>
   <string name="auth_testing_connection">Test de la connexion…</string>
   <string name="auth_not_configured_title">Configuration du serveur erronée</string>
-  <string name="auth_account_not_new">Un compte pour le même utilisateur et serveur existe déjà sur ce périphérique</string>
+  <string name="auth_account_not_new">Un compte pour le même utilisateur et serveur existe déjà sur cet appareil</string>
   <string name="auth_account_not_the_same">L\'utilisateur entré ne correspond pas à l\'utilisateur de ce compte</string>
-  <string name="auth_unknown_error_title">Une erreur inconnue s\'est produite</string>
+  <string name="auth_unknown_error_title">Une erreur inconnue s\'est produite.</string>
   <string name="auth_unknown_host_title">Impossible de trouver l\'hôte</string>
   <string name="auth_incorrect_path_title">Aucune instance du serveur n\'a été trouvée</string>
-  <string name="auth_timeout_title">Le serveur met trop longtemps à répondre</string>
+  <string name="auth_timeout_title">Le serveur a pris trop de temps à répondre</string>
   <string name="auth_incorrect_address_title">Adresse non valide</string>
   <string name="auth_ssl_general_error_title">Échec de l\'initialisation SSL</string>
   <string name="auth_ssl_unverified_server_title">Impossible de vérifier l\'identité du serveur SSL</string>
@@ -192,6 +192,7 @@ Ci-dessous la liste des fichiers locaux, et les fichiers distants dans %5$s auxq
   <string name="auth_fail_get_user_name">Votre serveur a retourné un identifiant d\'utilisateur incorrect. Veuillez prendre contact avec votre administrateur
 </string>
   <string name="auth_can_not_auth_against_server">Impossible de s\'authentifier sur ce serveur</string>
+  <string name="auth_account_does_not_exist">Le compte n\'existe pas encore sur ce périphérique</string>
   <string name="fd_keep_in_sync">Maintenir le fichier à jour</string>
   <string name="common_rename">Renommer</string>
   <string name="common_remove">Supprimer</string>
@@ -249,29 +250,31 @@ Ci-dessous la liste des fichiers locaux, et les fichiers distants dans %5$s auxq
   <string name="placeholder_media_time">12:23:45</string>
   <string name="instant_upload_on_wifi">Téléverser les images via une connexion WiFi uniquement</string>
   <string name="instant_video_upload_on_wifi">Téléverser les vidéos via une connexion WiFi uniquement</string>
-  <string name="instant_upload_path">/Instantané</string>
+  <string name="instant_upload_path">/InstantUpload</string>
   <string name="conflict_title">Conflit de mise à jour</string>
-  <string name="conflict_message">Le fichier distant %s n\'est pas synchronisé avec le fichier local. En choisissant de continuer, vous remplacerez le contenu de fichier sur le serveur.</string>
+  <string name="conflict_message">Le fichier distant %s n\'est pas synchronisé avec le fichier local. En choisissant de continuer, vous remplacerez le contenu du fichier sur le serveur.</string>
   <string name="conflict_keep_both">Garder les deux versions</string>
   <string name="conflict_overwrite">Écraser</string>
   <string name="conflict_dont_upload">Ne pas téléverser</string>
   <string name="preview_image_description">Prévisualisation de l\'image</string>
   <string name="preview_image_error_unknown_format">Cette image ne peut pas être affichée</string>
   <string name="error__upload__local_file_not_copied">%1$s n\'a pas pu être copié dans le dossier local %2$s</string>
-  <string name="prefs_instant_upload_path_title">Répertoire d\'envoi</string>
+  <string name="prefs_instant_upload_path_title">Répertoire de téléversement</string>
   <string name="share_link_no_support_share_api">Désolé, le partage n\'est pas disponible sur votre serveur. Veuillez contacter votre administrateur.</string>
   <string name="share_link_file_no_exist">Impossible de partager. Vérifiez que le fichier est bien présent</string>
   <string name="share_link_file_error">Une erreur est survenue lors de la tentative de partage de ce fichier ou répertoire</string>
   <string name="unshare_link_file_no_exist">Impossible de supprimer le partage. Vérifiez que le fichier est bien présent</string>
   <string name="unshare_link_file_error">Une erreur est survenue lors de la tentative d’annulation du partage de ce fichier ou répertoire</string>
+  <string name="share_link_password_title">Saisir un mot de passe</string>
+  <string name="share_link_empty_password">Vous devez saisir un mot de passe</string>
   <string name="activity_chooser_send_file_title">Envoyer</string>
   <string name="copy_link">Copier le lien</string>
   <string name="clipboard_text_copied">Copié dans le presse-papiers</string>
   <string name="error_cant_bind_to_operations_service">Erreur critique : impossible de réaliser des opérations</string>
-  <string name="network_error_socket_exception">Une erreur s\'est produite pendant la connection au serveur</string>
-  <string name="network_error_socket_timeout_exception">Une erreur est survenue pendant l\'attente du serveur. L\'opération n\'a pas pu être effectuée.</string>
-  <string name="network_error_connect_timeout_exception">Une erreur est survenue pendant l\'attente du serveur. L\'opération n\'a pas pu être effectuée.</string>
-  <string name="network_host_not_available">L\'opération n\'a pas pu être terminée, le serveur n\'est pas disponible.</string>
+  <string name="network_error_socket_exception">Une erreur est survenue pendant la connexion au serveur.</string>
+  <string name="network_error_socket_timeout_exception">Une erreur est survenue pendant l\'attente du serveur. L\'opération n\'a pas pu être effectuée</string>
+  <string name="network_error_connect_timeout_exception">Une erreur est survenue pendant l\'attente du serveur. L\'opération n\'a pas pu être effectuée</string>
+  <string name="network_host_not_available">L\'opération n\'a pas pu être terminée, le serveur n\'est pas disponible</string>
   <string name="empty"></string>
   <string name="forbidden_permissions">Vous ne possédez pas les droits suffisants %s</string>
   <string name="forbidden_permissions_rename">afin de renommer ce fichier</string>
@@ -283,12 +286,12 @@ Ci-dessous la liste des fichiers locaux, et les fichiers distants dans %5$s auxq
   <string name="downloader_download_file_not_found">Ce fichier n’est plus disponible sur le serveur</string>
   <string name="prefs_category_accounts">Comptes</string>
   <string name="prefs_add_account">Ajouter un compte</string>
-  <string name="auth_redirect_non_secure_connection_title">La connexion sécurisée est redirigée via une route non-sécurisée.</string>
+  <string name="auth_redirect_non_secure_connection_title">Le connexion sécurisée est redirigée vers une route non-sécurisée.</string>
   <string name="actionbar_logger">Journaux</string>
   <string name="log_send_history_button">Envoyer l\'historique</string>
-  <string name="log_send_no_mail_app">Aucune application trouvée pour envoyer les logs. Installez une application de courriel !</string>
+  <string name="log_send_no_mail_app">Aucune application trouvée pour l\'envoi de journaux. Installer une application de courriel !</string>
   <string name="log_send_mail_subject">Journaux de l\'application Android %1$s</string>
-  <string name="log_progress_dialog_text">Chargement des données...</string>
+  <string name="log_progress_dialog_text">Chargement des données</string>
   <string name="saml_authentication_required_text">Authentification requise</string>
   <string name="saml_authentication_wrong_pass">Mot de passe incorrect</string>
   <string name="actionbar_move">Déplacer</string>
@@ -299,11 +302,9 @@ Ci-dessous la liste des fichiers locaux, et les fichiers distants dans %5$s auxq
   <string name="move_file_invalid_overwrite">Le fichier existe déjà dans le dossier de destination</string>
   <string name="move_file_error">Une erreur est survenue lors de la tentative de déplacement de ce fichier ou dossier</string>
   <string name="forbidden_permissions_move">de déplacer ce fichier</string>
-  <string name="prefs_category_instant_uploading">Envoi instantané</string>
+  <string name="prefs_category_instant_uploading">Envois immédiats</string>
   <string name="prefs_category_security">Sécurité</string>
-  <string name="prefs_instant_video_upload_path_title">Répertoire d\'envoi des vidéos</string>
-  <string name="download_folder_failed_content">Le téléchargement du dossier %1$s n\'a pas pu être achevé complètement</string>
-  <string name="shared_subject_header">partagé(e)</string>
-  <string name="with_you_subject_header">avec vous</string>
-  <string name="subject_token">%1$s %2$s &gt;&gt;%3$s&lt;&lt; %4$s</string>
+  <string name="prefs_instant_video_upload_path_title">Répertoire de téléversement des vidéos</string>
+  <string name="download_folder_failed_content">Le téléchargement du dossier %1$s n\'a pas pu être achevé</string>
+  <string name="subject_token">%1$s a partagé \"%2$s\" avec vous</string>
 </resources>
index 616d482..85f91b0 100644 (file)
@@ -8,7 +8,7 @@
   <string name="actionbar_upload_files">Ficheiros</string>
   <string name="actionbar_open_with">Abrir con</string>
   <string name="actionbar_mkdir">Novo cartafol</string>
-  <string name="actionbar_settings">Preferencias</string>
+  <string name="actionbar_settings">Axustes</string>
   <string name="actionbar_see_details">Detalles</string>
   <string name="actionbar_send_file">Enviar</string>
   <string name="actionbar_sort">Ordenar</string>
@@ -188,6 +188,7 @@ Descárgueo de aquí: %2$s</string>
   <string name="auth_fail_get_user_name">O seu servidor non devolveu un ID de usuario correcto, contacte cun administrador
        </string>
   <string name="auth_can_not_auth_against_server">Non pode autenticarse neste servidor</string>
+  <string name="auth_account_does_not_exist">Aínda non existe a conta no dispositivo</string>
   <string name="fd_keep_in_sync">Manter actualizado o ficheiro</string>
   <string name="common_rename">Renomear</string>
   <string name="common_remove">Retirar</string>
@@ -261,6 +262,8 @@ Descárgueo de aquí: %2$s</string>
   <string name="share_link_file_error">Produciuse un erro ao tentar compartir este ficheiro ou cartafol.</string>
   <string name="unshare_link_file_no_exist">Non foi posíbel deixar de compartir. Comprobe que existe o ficheiro</string>
   <string name="unshare_link_file_error">Produciuse un erro ao tentar deixar de compartir este ficheiro ou cartafol</string>
+  <string name="share_link_password_title">Escriba un contrasinal</string>
+  <string name="share_link_empty_password">Ten que escribir un contrasinal</string>
   <string name="activity_chooser_send_file_title">Enviar</string>
   <string name="copy_link">Copiar a ligazón</string>
   <string name="clipboard_text_copied">Copiado no portapapeis.</string>
@@ -299,8 +302,6 @@ Descárgueo de aquí: %2$s</string>
   <string name="prefs_category_instant_uploading">Envío instantáneo</string>
   <string name="prefs_category_security">Seguranza</string>
   <string name="prefs_instant_video_upload_path_title">Enviar a ruta do vídeo</string>
-  <string name="download_folder_failed_content">A descarga do cartafol %1$s non se puido completar</string>
-  <string name="shared_subject_header">compartido</string>
-  <string name="with_you_subject_header">con vostede</string>
-  <string name="subject_token">%1$s %2$s &gt;&gt;%3$s&lt;&lt; %4$s</string>
+  <string name="download_folder_failed_content">Non foi posíbel completar a descarga do cartafol %1$s</string>
+  <string name="subject_token">%1$s compartiu «%2$s» con vostede</string>
 </resources>
index e8d1111..ff42f94 100644 (file)
   <string name="actionbar_move">Mozgatás</string>
   <string name="folder_picker_choose_button_text">Válasszon</string>
   <string name="prefs_category_security">Biztonság</string>
-  <string name="shared_subject_header">Megosztott</string>
 </resources>
index eb2df51..1b0dd76 100644 (file)
   <string name="forbidden_permissions_move">untuk memindahkan berkas ini</string>
   <string name="prefs_category_instant_uploading">Unggah Cepat</string>
   <string name="prefs_category_security">Keamanan</string>
-  <string name="shared_subject_header">dibagikan</string>
 </resources>
index 9cca628..465db72 100644 (file)
   <string name="auth_fail_get_user_name">Il tuo server non ha restituito un id utente corretto, contatta un amministratore
        </string>
   <string name="auth_can_not_auth_against_server">Impossibile eseguire l\'autenticazione su questo server</string>
+  <string name="auth_account_does_not_exist">L\'account non esiste ancora sul dispositivo</string>
   <string name="fd_keep_in_sync">Tieni aggiornato il file</string>
   <string name="common_rename">Rinomina</string>
   <string name="common_remove">Rimuovi</string>
   <string name="share_link_file_error">Si è verificato un errore durante il tentativo di condivisione del file o della cartella</string>
   <string name="unshare_link_file_no_exist">Impossibile rimuovere dalla condivisione. Assicurati che il file esista</string>
   <string name="unshare_link_file_error">Si è verificato un errore durante il tentativo di rimuovere la condivisione del file o della cartella</string>
+  <string name="share_link_password_title">Digita una password</string>
+  <string name="share_link_empty_password">Devi digitare una password</string>
   <string name="activity_chooser_send_file_title">Invia</string>
   <string name="copy_link">Copia collegamento</string>
   <string name="clipboard_text_copied">Copiato negli appunti</string>
   <string name="prefs_category_security">Protezione</string>
   <string name="prefs_instant_video_upload_path_title">Percorso di caricamento video</string>
   <string name="download_folder_failed_content">Lo scaricamento della cartella %1$s non può essere completato</string>
-  <string name="shared_subject_header">condiviso</string>
-  <string name="with_you_subject_header">con te</string>
-  <string name="subject_token">%1$s %2$s &gt;&gt;%3$s&lt;&lt; %4$s</string>
+  <string name="subject_token">%1$s ha condiviso \"%2$s\" con te</string>
 </resources>
index d3f9e7b..489c22a 100644 (file)
   <string name="auth_connecting_auth_server">認証サーバーに接続中 ...</string>
   <string name="auth_unsupported_auth_method">サーバーはこの認証方式をサポートしていません</string>
   <string name="auth_unsupported_multiaccount">%1$s は複数アカウントをサポートしていません</string>
-  <string name="auth_fail_get_user_name">サーバーが正しいユーザーIDを返しませんでした。管理者にご連絡ください。
+  <string name="auth_fail_get_user_name">サーバーが正しいユーザーIDを返しませんでした。管理者に連絡してください。
        </string>
   <string name="auth_can_not_auth_against_server">このサーバーに対して認証できません</string>
+  <string name="auth_account_does_not_exist">デバイス上にまだアカウントが存在しません</string>
   <string name="fd_keep_in_sync">ファイルを最新に保つ</string>
   <string name="common_rename">名前を変更</string>
   <string name="common_remove">削除</string>
   <string name="placeholder_filesize">389 KB</string>
   <string name="placeholder_timestamp">2012/05/18 12:23 PM</string>
   <string name="placeholder_media_time">12:23:45</string>
-  <string name="instant_upload_on_wifi">WiFi経由でのみ写真をアップロード</string>
+  <string name="instant_upload_on_wifi">WiFi経由でのみ画像をアップロード</string>
   <string name="instant_video_upload_on_wifi">WiFi経由でのみ動画をアップロード</string>
   <string name="instant_upload_path">/InstantUpload</string>
   <string name="conflict_title">更新が競合</string>
   <string name="preview_image_error_unknown_format">この画像は表示できません</string>
   <string name="error__upload__local_file_not_copied">%1$s は、ローカルフォルダー %2$s  にコピーできませんでした。</string>
   <string name="prefs_instant_upload_path_title">アップロードパス</string>
-  <string name="share_link_no_support_share_api">申し訳ございません。共有がサーバー上で有効になっていません。 管理者に
-               ご連絡ください。</string>
+  <string name="share_link_no_support_share_api">すみませんが、サーバーで共有が有効になっていません。
+               管理者に連絡してください。</string>
   <string name="share_link_file_no_exist">共有できません。ファイルがあるか確認してください。</string>
   <string name="share_link_file_error">このファイルまたはフォルダーを共有する際にエラーが発生しました</string>
   <string name="unshare_link_file_no_exist">共有を解除できません。ファイルがあるか確認してください。</string>
   <string name="unshare_link_file_error">このファイルまたはフォルダーの共有を解除する際にエラーが発生しました</string>
+  <string name="share_link_password_title">パスワードを入力</string>
+  <string name="share_link_empty_password">パスワードを入力しなければなりません</string>
   <string name="activity_chooser_send_file_title">送信</string>
   <string name="copy_link">リンクをコピー</string>
   <string name="clipboard_text_copied">クリップボードにコピー</string>
   <string name="prefs_category_instant_uploading">自動アップロード</string>
   <string name="prefs_category_security">セキュリティ</string>
   <string name="prefs_instant_video_upload_path_title">動画のアップロードパス</string>
-  <string name="shared_subject_header">共有中</string>
-  <string name="with_you_subject_header">あなたと</string>
-  <string name="subject_token">%1$s %2$s &gt;&gt;%3$s&lt;&lt; %4$s</string>
+  <string name="download_folder_failed_content">%1$s のフォルダのダウンロードが完了しませんでした。</string>
+  <string name="subject_token">%1$sがあなたと\"%2$s\"を共有しました</string>
 </resources>
index 535f76b..cc48be1 100644 (file)
@@ -2,7 +2,9 @@
 <resources>
   <string name="about_android">%1$s កម្មវិធីអានដ្រយ</string>
   <string name="about_version">ជំនាន់ %1$s</string>
+  <string name="actionbar_sync">គណនីឱ្យថ្មីឡើងវិញ</string>
   <string name="actionbar_upload">ផ្ទុក​ឡើង</string>
+  <string name="actionbar_upload_from_apps">មាតិការ​ពីកម្មវិធីផ្សេងទៀត</string>
   <string name="actionbar_upload_files">ឯកសារ</string>
   <string name="actionbar_open_with">បើកជាមួយ</string>
   <string name="actionbar_mkdir">ថត​ថ្មី</string>
   <string name="prefs_accounts">គណនី</string>
   <string name="prefs_manage_accounts">គ្រប់គ្រង​គណនី</string>
   <string name="prefs_pincode">ភីន​កូដ កម្មវិធី</string>
+  <string name="prefs_log_title">ដំណើរការការចូលទៅកាន់</string>
+  <string name="prefs_log_summary">នេះជាបញ្ហា​សម្រាប់​អ្នក​ដែល​បាន​ចូលទៅកាន់</string>
+  <string name="prefs_log_title_history">ប្រវត្តិនៃការចូលទៅកាន់</string>
+  <string name="prefs_log_summary_history">នៅទីនេះ​គឺបង្ហាញការដែលបាន​ចូលទៅកាន់</string>
+  <string name="prefs_log_delete_history_button">លុប​ប្រវត្តិ</string>
   <string name="prefs_help">ជំនួយ</string>
+  <string name="prefs_recommend">ផ្ដល់អនុសាសន៍ទៅកាន់មិត្តភក្ដិ</string>
+  <string name="prefs_feedback">មតិត្រឡប់</string>
   <string name="auth_username">ឈ្មោះ​អ្នកប្រើ</string>
   <string name="auth_password">ពាក្យសម្ងាត់</string>
   <string name="sync_string_files">ឯកសារ</string>
index ef683c1..973ac89 100644 (file)
   <string name="auth_fail_get_user_name">서버에서 올바른 사용자 ID를 반환하지 않았습니다. 관리자에게 연락하십시오
        </string>
   <string name="auth_can_not_auth_against_server">이 서버에 인증할 수 없음</string>
+  <string name="auth_account_does_not_exist">장치에 아직 계정이 존재하지 않습니다.</string>
   <string name="fd_keep_in_sync">파일을 최신 정보로 유지</string>
   <string name="common_rename">이름 바꾸기</string>
   <string name="common_remove">삭제</string>
   <string name="share_link_file_error">이 파일이나 폴더를 공유하는 중 오류 발생</string>
   <string name="unshare_link_file_no_exist">공유를 해제할 수 없습니다. 파일이 있는지 확인하십시오</string>
   <string name="unshare_link_file_error">이 파일이나 폴더의 공유를 해제하는 중 오류 발생</string>
+  <string name="share_link_password_title">비밀번호를 입력하십시요.</string>
+  <string name="share_link_empty_password">비밀번호를 입력해야만 합니다.</string>
   <string name="activity_chooser_send_file_title">보내기</string>
   <string name="copy_link">링크 주소 복사</string>
   <string name="clipboard_text_copied">클립보드로 복사됨</string>
   <string name="prefs_category_instant_uploading">즉시 업로드</string>
   <string name="prefs_category_security">보안</string>
   <string name="prefs_instant_video_upload_path_title">동영상 업로드 경로</string>
-  <string name="shared_subject_header">공유됨</string>
-  <string name="with_you_subject_header">나와</string>
-  <string name="subject_token">%1$s %2$s &gt;&gt;%3$s&lt;&lt; %4$s</string>
+  <string name="download_folder_failed_content">%1$s 폴더를 다운로드할 수 없습니다</string>
+  <string name="subject_token">%1$s에서 \"%2$s\"를 당신과 공유하였습니다.</string>
 </resources>
index 9feccd8..09b11cc 100644 (file)
@@ -2,7 +2,7 @@
 <!--
   ownCloud Android client application
 
-  Copyright (C) 2012-2013 ownCloud Inc.
+  Copyright (C) 2015 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,
index b8c3bb1..76e0e52 100644 (file)
   <string name="saml_authentication_wrong_pass">Neteisingas slaptažodis</string>
   <string name="folder_picker_choose_button_text">Pasirinkite</string>
   <string name="prefs_category_security">Saugumas</string>
-  <string name="shared_subject_header">bendrinamas</string>
 </resources>
index 0895ca9..e9b3b24 100644 (file)
@@ -3,9 +3,12 @@
   <string name="actionbar_upload">Augšupielādēt</string>
   <string name="actionbar_upload_from_apps">Saturs no citām lietotnēm</string>
   <string name="actionbar_upload_files">Datnes</string>
+  <string name="actionbar_open_with">Atvērt ar</string>
   <string name="actionbar_mkdir">Jauna mape</string>
   <string name="actionbar_settings">Iestatījumi</string>
   <string name="actionbar_send_file">Sūtīt</string>
+  <string name="actionbar_sort">Kārtot</string>
+  <string name="actionbar_sort_title">Kārtot pēc</string>
   <!--TODO re-enable when server-side folder size calculation is available   
        <item>Biggest - Smallest</item>-->
   <string name="prefs_category_general">Vispārīgi</string>
index 23c3611..2ce829c 100644 (file)
   <string name="saml_authentication_wrong_pass">Погрешна лозинка</string>
   <string name="folder_picker_choose_button_text">Избери</string>
   <string name="prefs_category_security">Безбедност</string>
-  <string name="shared_subject_header">споделен</string>
 </resources>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
new file mode 100644 (file)
index 0000000..69623e1
--- /dev/null
@@ -0,0 +1,6 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<resources>
+  <!--TODO re-enable when server-side folder size calculation is available   
+       <item>Biggest - Smallest</item>-->
+  <string name="empty"></string>
+</resources>
index 859c7c9..3336ec1 100644 (file)
@@ -12,7 +12,7 @@
   <string name="actionbar_see_details">Detaljer</string>
   <string name="actionbar_send_file">Send</string>
   <string name="actionbar_sort">Sorter</string>
-  <string name="actionbar_sort_title">Sorter </string>
+  <string name="actionbar_sort_title">Sorter etter</string>
   <string-array name="actionbar_sortby">
     <item>A-Z</item>
     <item>Nyeste - Eldste</item>
   <string name="prefs_category_instant_uploading">Umiddelbare opplastinger</string>
   <string name="prefs_category_security">Sikkerhet</string>
   <string name="prefs_instant_video_upload_path_title">Sti til video-opplasting</string>
-  <string name="shared_subject_header">delt</string>
-  <string name="with_you_subject_header">med deg</string>
-  <string name="subject_token">%1$s %2$s &gt;&gt;%3$s&lt;&lt; %4$s</string>
+  <string name="download_folder_failed_content">Nedlasting av %1$s mappen kunne ikke fullføres</string>
 </resources>
index 482a279..8cfb96d 100644 (file)
@@ -190,6 +190,7 @@ Hieronder staan de lokale bestanden en de externe bestanden in %5$s waar ze naar
   <string name="auth_fail_get_user_name">Uw server geeft geen goede userid terug, neem contact op met uw beheerder
        </string>
   <string name="auth_can_not_auth_against_server">Kan niet authenticeren tegen deze server</string>
+  <string name="auth_account_does_not_exist">Het account bestaat nog niet in dit apparaat</string>
   <string name="fd_keep_in_sync">Houd bestand actueel</string>
   <string name="common_rename">Hernoemen</string>
   <string name="common_remove">Verwijderen</string>
@@ -263,6 +264,8 @@ Hieronder staan de lokale bestanden en de externe bestanden in %5$s waar ze naar
   <string name="share_link_file_error">Er trad een fout op bij uw poging dit bestand of deze map te delen</string>
   <string name="unshare_link_file_no_exist">Kan delen niet beëindigen. Ga na of het bestand bestaat</string>
   <string name="unshare_link_file_error">Er trad een fout op bij uw poging het delen van dit bestand of deze map te beëindigen</string>
+  <string name="share_link_password_title">Vul het wachtwoord in</string>
+  <string name="share_link_empty_password">U moet een wachtwoord opgeven</string>
   <string name="activity_chooser_send_file_title">Versturen</string>
   <string name="copy_link">Link kopiëren</string>
   <string name="clipboard_text_copied">Gekopieerd naar het klembord</string>
@@ -302,7 +305,5 @@ Hieronder staan de lokale bestanden en de externe bestanden in %5$s waar ze naar
   <string name="prefs_category_security">Beveiliging</string>
   <string name="prefs_instant_video_upload_path_title">Upload Video Pad</string>
   <string name="download_folder_failed_content">Download van %1$s map kon niet worden voltooid</string>
-  <string name="shared_subject_header">gedeeld</string>
-  <string name="with_you_subject_header">met u</string>
-  <string name="subject_token">%1$s %2$s &gt;&gt;%3$s&lt;&lt; %4$s</string>
+  <string name="subject_token">%1$s deelde \"%2$s\" met u</string>
 </resources>
index cc0f5b4..3623617 100644 (file)
@@ -39,6 +39,7 @@
   <string name="prefs_feedback">Wsparcie</string>
   <string name="prefs_imprint">Stopka</string>
   <string name="prefs_remember_last_share_location">Zapamiętaj położenie udostępnienia</string>
+  <string name="prefs_remember_last_upload_location_summary">Zapamiętaj ostatnią lokalizację wgrywania</string>
   <string name="recommend_subject">Wypróbuj %1$s na swoim smartphonie!</string>
   <string name="recommend_text">Chciałbym zaprosić Cię do używania %1$s na swoim smartfonie!\nŚciągnij tutaj: %2$s</string>
   <string name="auth_check_server">Sprawdź serwer</string>
   <string name="auth_redirect_non_secure_connection_title">Bezpieczne połączenie jest przekierowywane przez niezabezpieczone trasy.</string>
   <string name="actionbar_logger">Logi</string>
   <string name="log_send_history_button">Wyślij historię</string>
+  <string name="log_send_no_mail_app">Brak aplikacji do wysyłania logów. Zainstaluj klienta poczty!</string>
   <string name="log_send_mail_subject">%1$s Logi aplikacji Android</string>
   <string name="log_progress_dialog_text">Ładuję dane...</string>
   <string name="saml_authentication_required_text">Wymagana autoryzacja</string>
   <string name="prefs_category_instant_uploading">Automatyczne wysyłanie</string>
   <string name="prefs_category_security">Bezpieczeństwo</string>
   <string name="prefs_instant_video_upload_path_title">Katalog wysyłania dla wideo</string>
-  <string name="shared_subject_header">współdzielone</string>
+  <string name="download_folder_failed_content">Pobieranie %1$s katalogu nie może zostać ukończone</string>
 </resources>
index 7e02b56..0eecfea 100644 (file)
   <string name="auth_fail_get_user_name">Seu servidor não está retornando um ID de usuário correto, por favor, entre em contato com um administrador
 ⇥</string>
   <string name="auth_can_not_auth_against_server">Não foi possível autenticar neste servidor</string>
+  <string name="auth_account_does_not_exist">Conta ainda não existe no dispositivo</string>
   <string name="fd_keep_in_sync">Manter arquivo atualizado</string>
   <string name="common_rename">Renomear</string>
   <string name="common_remove">Remover</string>
   <string name="share_link_file_error">Ocorreu um erro durante a tentativa de compartilhar esse arquivo ou pasta</string>
   <string name="unshare_link_file_no_exist">Não é possível cancelar o compartilhamento. Por favor verifique se o arquivo existe</string>
   <string name="unshare_link_file_error">Ocorreu um erro ao tentar descompartilhar este arquivo ou pasta</string>
+  <string name="share_link_password_title">Digite uma senha</string>
+  <string name="share_link_empty_password">Você deve digitar uma senha</string>
   <string name="activity_chooser_send_file_title">Enviar</string>
   <string name="copy_link">Copiar o link</string>
   <string name="clipboard_text_copied">Copiado para área de transferência</string>
   <string name="prefs_category_instant_uploading">Envios Instantâneos</string>
   <string name="prefs_category_security">Segurança</string>
   <string name="prefs_instant_video_upload_path_title">Enviar o Caminho do Vídeo</string>
-  <string name="shared_subject_header">compartilhado</string>
-  <string name="with_you_subject_header">com você</string>
-  <string name="subject_token">%1$s %2$s &gt;&gt;%3$s&lt;&lt; %4$s</string>
+  <string name="download_folder_failed_content">Baixar %1$s da pasta não pode ser completado</string>
+  <string name="subject_token">%1$s compartilhou \"%2$s\" com você</string>
 </resources>
index efadb60..ce2a645 100644 (file)
   <string name="auth_unsupported_multiaccount">%1$s não suporta contas múltiplas</string>
   <string name="auth_fail_get_user_name">O seu servidor não transmite o ID correcto. Por favor contacte o administrador.</string>
   <string name="auth_can_not_auth_against_server">Não foi possível autenticar no servidor</string>
+  <string name="auth_account_does_not_exist">Conta ainda não existe no dispositivo</string>
   <string name="fd_keep_in_sync">manter ficheiro actualizado</string>
   <string name="common_rename">Renomear</string>
   <string name="common_remove">Remover</string>
   <string name="share_link_file_error">Ocorreu um erro enquanto tentava partilhar este ficheiro ou pasta</string>
   <string name="unshare_link_file_no_exist">Não é possível retirar a partilha. Verifique se o ficheiro existe</string>
   <string name="unshare_link_file_error">Ocorreu um erro enquanto retirava a partilha deste ficheiro ou pasta</string>
+  <string name="share_link_password_title">Introduza uma palavra-passe</string>
+  <string name="share_link_empty_password">Você deve introduzir uma palavra-passe</string>
   <string name="activity_chooser_send_file_title">Enviar</string>
   <string name="copy_link">Copiar hiperligação</string>
   <string name="clipboard_text_copied">Copiado para a área de transferência</string>
   <string name="prefs_category_instant_uploading">Envios Instantâneos</string>
   <string name="prefs_category_security">Segurança</string>
   <string name="prefs_instant_video_upload_path_title">Envio do Caminho do Vídeo</string>
-  <string name="shared_subject_header">partilhado</string>
-  <string name="with_you_subject_header">consigo</string>
-  <string name="subject_token">%1$s %2$s &gt;&gt;%3$s&lt;&lt; %4$s</string>
+  <string name="download_folder_failed_content">Não foi possível completar o download da pasta %1$s</string>
+  <string name="subject_token">%1$s partilhou \"%2$s\" consigo</string>
 </resources>
index 74c1b55..9b333e6 100644 (file)
   <string name="prefs_recommend">Recomandati unui prieten</string>
   <string name="prefs_feedback">Feedback</string>
   <string name="prefs_imprint">Imprint</string>
+  <string name="prefs_remember_last_share_location">Reține contribuie locația</string>
+  <string name="prefs_remember_last_upload_location_summary">Reține locația fișierului încărcat precedent</string>
   <string name="recommend_subject">Încearcă %1$s pe smartphone-ul tău!</string>
+  <string name="recommend_text">Te invit sa folosești %1$s pe smartfonul tău!\nDescarcă aici: %2$s</string>
   <string name="auth_check_server">Verificaţi Serverul</string>
   <string name="auth_host_url">Adresa serverului https://...</string>
   <string name="auth_username">Nume utilizator</string>
   <string name="sync_fail_in_favourites_content">Conținutul a%1$d fișiere nu a putut fi sincronizat (conflicte %2$d)</string>
   <string name="sync_foreign_files_forgotten_ticker">Unele fisiere locale au fost uitate</string>
   <string name="sync_foreign_files_forgotten_content">%1$d fisiere din  dosarul  %2$s nu a putut fi copiat in</string>
+  <string name="sync_foreign_files_forgotten_explanation">Conform ediției 1.3.16, fișierele încărcate de pe această platformă sunt copiate în dosarul local %1$s pentru a preveni pierderi de date atunci cînd un singur fișier este sincronizat cu mai multe conturi.\n\nDin cauza acestei schimbări, toate fișierele încărcate în edițiile precedente ale acestui app au fost încărcate in dosarul %2$s. Însă acest proces nu fost completat in timpul sincronizării contului din cauza unei erori. Ai opțiunea de a lăsa fișierul intact (fișierele intacte) și de a transfera sursa în dosarul %3$s sau de a schimba locația fișierului(-elor) în dosarul %1$s și de a păstra sursa în %4$s.\n\nMai jos găsești enumerate fișierul local(fișierele locale) și fișierul separat(fișierele separate) în %5$s cu sursa respectivă.</string>
   <string name="sync_current_folder_was_removed">Folderul %1$s nu mai există</string>
   <string name="foreign_files_move">Muta tot/toate</string>
   <string name="foreign_files_success">Toate fişierele au fost mutate</string>
   <string name="auth_unsupported_multiaccount">%1$s nu suporta conturi multiple</string>
   <string name="auth_fail_get_user_name">Server-ul dvs. nu  întoarce un ID de utilizator corect, vă rugăm să contactați un administrator </string>
   <string name="auth_can_not_auth_against_server">Nu se poate autentifica cu acest server</string>
+  <string name="auth_account_does_not_exist">Contul nu există încă în dispozitiv</string>
   <string name="fd_keep_in_sync">Păstrează fișierul actualizat</string>
   <string name="common_rename">Redenumește</string>
   <string name="common_remove">Elimină</string>
   <string name="preview_image_description">Previzualizare imagine</string>
   <string name="preview_image_error_unknown_format">Aceasta imagine nu poate fi arătată</string>
   <string name="error__upload__local_file_not_copied">%1$s nu a putut fi copiat in dosarul local %2$s </string>
+  <string name="prefs_instant_upload_path_title">Calea de încărcare</string>
   <string name="share_link_no_support_share_api">Ne pare rău, partajarea nu este activată pe server. Vă rugăm să contactați administratorul dvs.</string>
   <string name="share_link_file_error">A apărut o eroare în timp ce încerca să partajeze acest fișier sau folder</string>
   <string name="unshare_link_file_error">A apărut o eroare în timp ce încerca să departajeze sau unshare acest fișier sau folder</string>
   <string name="downloader_download_file_not_found">Fișierul nu mai este disponibil pe server</string>
   <string name="prefs_category_accounts">Conturi</string>
   <string name="prefs_add_account">Adaugă cont</string>
+  <string name="auth_redirect_non_secure_connection_title">Conexiunea securizată este redirecționată către un traseu neasigurat.</string>
+  <string name="actionbar_logger">Înregistrări</string>
+  <string name="log_send_history_button">Trimite Istoria</string>
+  <string name="log_send_no_mail_app">App-ul de trimitere a inregistrărilor nu a fost găsit. Instalează mail app-ul!</string>
+  <string name="log_send_mail_subject">%1$s înregistrările app-ului Android</string>
+  <string name="log_progress_dialog_text">Datele se încarcă...</string>
   <string name="saml_authentication_required_text">Autentificare necesară</string>
   <string name="saml_authentication_wrong_pass">Parolă greșită</string>
   <string name="actionbar_move">Mutare</string>
   <string name="file_list_empty_moving">Nu este nimic aici. Poți adăuga un director!</string>
   <string name="folder_picker_choose_button_text">Alege</string>
+  <string name="move_file_not_found">Incapabil de trasfer. Verifică existența fișierului</string>
+  <string name="move_file_invalid_overwrite">Fișierul există deja în dosarul de destinație</string>
+  <string name="move_file_error">O eroare apare la transferarea acestui fișier sau dosar</string>
   <string name="forbidden_permissions_move">pentru a muta acest fișier</string>
   <string name="prefs_category_instant_uploading">Încărcări instante</string>
   <string name="prefs_category_security">Securitate</string>
+  <string name="prefs_instant_video_upload_path_title">Calea de încărcare Video</string>
+  <string name="download_folder_failed_content">Descărcarea fișierului %1$s nu s-a finisat</string>
 </resources>
index 0c98373..c47e73d 100644 (file)
@@ -28,7 +28,7 @@
   <string name="prefs_instant_upload">Мгновенная загрузка фотографий</string>
   <string name="prefs_instant_upload_summary">Немедленно загружать фотографии сделанные камерой</string>
   <string name="prefs_instant_video_upload">Мгновенная загрузка видео</string>
-  <string name="prefs_instant_video_upload_summary">Немедленно загружать видео сделанные камерой</string>
+  <string name="prefs_instant_video_upload_summary">Немедленно загружать видео, сделанные камерой</string>
   <string name="prefs_log_title">Включить журналирование</string>
   <string name="prefs_log_summary">Используется для регистрации ошибок</string>
   <string name="prefs_log_title_history">Журнал</string>
@@ -53,7 +53,7 @@
   <string name="uploader_btn_upload_text">Загрузить</string>
   <string name="uploader_top_message">Выберите каталог для загрузки</string>
   <string name="uploader_wrn_no_account_title">Учётная запись не найдена</string>
-  <string name="uploader_wrn_no_account_text">На вашем устройстве нет учётных записей %1$s. Пожалуйста настройте учётную запись.</string>
+  <string name="uploader_wrn_no_account_text">На вашем устройстве нет учётных записей %1$s. Пожалуйста, настройте учётную запись.</string>
   <string name="uploader_wrn_no_account_setup_btn_text">Настройка</string>
   <string name="uploader_wrn_no_account_quit_btn_text">Выход</string>
   <string name="uploader_wrn_no_content_title">Нет содержимого для загрузки</string>
   <string name="auth_fail_get_user_name">Сервер вернул некорректный пользовательский идентификатор. Пожалуйста, свяжитесь с вашим администратором
 ⇥</string>
   <string name="auth_can_not_auth_against_server">Невозможно авторизоваться на этом сервере</string>
+  <string name="auth_account_does_not_exist">Аккаунт не существует на устройстве ещё</string>
   <string name="fd_keep_in_sync">Обновлять файл</string>
   <string name="common_rename">Переименовать</string>
   <string name="common_remove">Удалить</string>
   <string name="share_link_file_error">При попытке поделиться этим файлом или каталогом произошла ошибка</string>
   <string name="unshare_link_file_no_exist">Невозможно закрыть доступ. Убедитесь что файл существует</string>
   <string name="unshare_link_file_error">При попытке закрыть доступ к этому файлу или каталогу произошла ошибка</string>
+  <string name="share_link_password_title">Введите пароль</string>
+  <string name="share_link_empty_password">Вы должны ввести пароль</string>
   <string name="activity_chooser_send_file_title">Отправить</string>
   <string name="copy_link">Копировать ссылку</string>
   <string name="clipboard_text_copied">Скопировано в буфер обмена</string>
   <string name="prefs_category_security">Безопасность</string>
   <string name="prefs_instant_video_upload_path_title">Путь для загрузки Видео</string>
   <string name="download_folder_failed_content">Загрузка папки %1$s не может быть завершена</string>
-  <string name="shared_subject_header">общие</string>
-  <string name="with_you_subject_header">с вами</string>
-  <string name="subject_token">%1$s %2$s &gt;&gt;%3$s&lt;&lt; %4$s</string>
+  <string name="subject_token">%1$s предоставил вам доступ к \"%2$s\"</string>
 </resources>
index 04ff620..9a70c22 100644 (file)
   <string name="auth_fail_get_user_name">Váš server nevracia správne používateľské id, kontaktujte prosím správcu systému
        </string>
   <string name="auth_can_not_auth_against_server">Nie je možné vykonať autentifikáciu na server</string>
+  <string name="auth_account_does_not_exist">Účet zatiaľ v zariadení neexistuje</string>
   <string name="fd_keep_in_sync">Udržiavať súbor aktuálny.</string>
   <string name="common_rename">Premenuj</string>
   <string name="common_remove">Odober</string>
   <string name="prefs_category_security">Zabezpečenie</string>
   <string name="prefs_instant_video_upload_path_title">Cesta pre nahrávanie videí</string>
   <string name="download_folder_failed_content">Sťahovanie %1$s priečinka nebolo dokončené</string>
-  <string name="shared_subject_header">zdieľané</string>
-  <string name="with_you_subject_header">s vami</string>
-  <string name="subject_token">%1$s %2$s &gt;&gt;%3$s&lt;&lt; %4$s</string>
+  <string name="subject_token">%1$s vám zdieľa „%2$s“</string>
 </resources>
index 7f1a625..7a2f2ba 100644 (file)
   <string name="auth_fail_get_user_name">Strežnik ne vrača ustreznega ID uporabnika. Stopite v stik s skrbnikom sistema.
        </string>
   <string name="auth_can_not_auth_against_server">Ni mogoče preveriti pristnosti strežnika</string>
+  <string name="auth_account_does_not_exist">Račun na napravi še ne obstaja.</string>
   <string name="fd_keep_in_sync">Datoteka naj bo posodobljena</string>
   <string name="common_rename">Preimenuj</string>
   <string name="common_remove">Odstrani</string>
   <string name="share_link_file_error">Prišlo je do napake med poskusom omogočanja souporabe te datoteke ali mape</string>
   <string name="unshare_link_file_no_exist">Ni mogoče prekiniti souporabe. Preverite, ali datoteka obstaja.</string>
   <string name="unshare_link_file_error">Prišlo je do napake med poskusom odstranjevanja souporabe te datoteke ali mape</string>
+  <string name="share_link_password_title">Vpis gesla</string>
+  <string name="share_link_empty_password">Vpisati je treba geslo.</string>
   <string name="activity_chooser_send_file_title">Pošlji</string>
   <string name="copy_link">Kopiraj povezavo</string>
   <string name="clipboard_text_copied">Kopirano v odložišče</string>
   <string name="prefs_category_instant_uploading">Takojšnje pošiljanje v oblak</string>
   <string name="prefs_category_security">Varnost</string>
   <string name="prefs_instant_video_upload_path_title">Pot videa za pošiljanje</string>
-  <string name="shared_subject_header">v souporabi</string>
-  <string name="with_you_subject_header">z vami</string>
-  <string name="subject_token">%1$s %2$s &gt;&gt;%3$s&lt;&lt; %4$s</string>
+  <string name="download_folder_failed_content">Imenika %1$s  ni mogoče prejeti v celoti</string>
+  <string name="subject_token">Uporabnik %1$s je omogočil souporabo \"%2$s\".</string>
 </resources>
index 7c1b7ff..02918e8 100644 (file)
@@ -77,5 +77,4 @@
   <string name="saml_authentication_wrong_pass">Fjalëkalim i gabuar</string>
   <string name="folder_picker_choose_button_text">Zgjidh</string>
   <string name="prefs_category_security">Siguria</string>
-  <string name="shared_subject_header">Ndarë</string>
 </resources>
index b9235ad..bd0abcc 100644 (file)
 <?xml version='1.0' encoding='UTF-8'?>
 <resources>
+  <string name="about_android">%1$s Андроид апликација</string>
+  <string name="about_version">верзија %1$s</string>
+  <string name="actionbar_sync">Освежи налог</string>
   <string name="actionbar_upload">Отпреми</string>
-  <string name="actionbar_upload_from_apps">Садржај са других апликација</string>
-  <string name="actionbar_upload_files">Датотеке</string>
+  <string name="actionbar_upload_from_apps">Садржај из других апликација</string>
+  <string name="actionbar_upload_files">Фајлови</string>
+  <string name="actionbar_open_with">Отвори помоћу</string>
+  <string name="actionbar_mkdir">Нова фасцикла</string>
   <string name="actionbar_settings">Поставке</string>
+  <string name="actionbar_see_details">Детаљи</string>
   <string name="actionbar_send_file">Пошаљи</string>
+  <string name="actionbar_sort">Разврстај</string>
+  <string name="actionbar_sort_title">Разврставање</string>
+  <string-array name="actionbar_sortby">
+    <item>A-Z</item>
+    <item>новији - старији</item>
+  </string-array>
   <!--TODO re-enable when server-side folder size calculation is available   
        <item>Biggest - Smallest</item>-->
   <string name="prefs_category_general">Опште</string>
   <string name="prefs_category_more">Више</string>
   <string name="prefs_accounts">Налози</string>
+  <string name="prefs_manage_accounts">Управљање налозима</string>
+  <string name="prefs_pincode">ПИБ апликације</string>
+  <string name="prefs_pincode_summary">Заштитите програм</string>
+  <string name="prefs_instant_upload">Тренутно отпремање фотографија</string>
+  <string name="prefs_instant_upload_summary">Тренутно отпремај фотографије сликане камером</string>
+  <string name="prefs_instant_video_upload">Тренутно отпремање видеа</string>
+  <string name="prefs_instant_video_upload_summary">Тренутно отпремај видео снимљен камером</string>
+  <string name="prefs_log_title">Укључи бележење</string>
+  <string name="prefs_log_summary">Ово се користи за бележење проблема</string>
+  <string name="prefs_log_title_history">Историјат бележења</string>
+  <string name="prefs_log_summary_history">Ово приказује сачуване записнике</string>
+  <string name="prefs_log_delete_history_button">Обриши историјат</string>
   <string name="prefs_help">Помоћ</string>
+  <string name="prefs_recommend">Препоручи пријатељу</string>
+  <string name="prefs_feedback">Ваше мишљење</string>
+  <string name="prefs_imprint">Жиг</string>
+  <string name="prefs_remember_last_share_location">Упамти локацију дељења</string>
+  <string name="prefs_remember_last_upload_location_summary">Памти последњу локацију отпремања дељења</string>
+  <string name="recommend_subject">Пробајте %1$s на вашем телефону!</string>
+  <string name="recommend_text">Предлажем вам да пробате %1$s на вашем телефону!\nПреузмите овде: %2$s</string>
+  <string name="auth_check_server">Провери сервер</string>
+  <string name="auth_host_url">Адреса сервера https://…</string>
   <string name="auth_username">Корисничко име</string>
   <string name="auth_password">Лозинка</string>
+  <string name="auth_register">Нов вам је %1$s?</string>
   <string name="sync_string_files">Фајлови</string>
-  <string name="setup_btn_connect">Повежи ме</string>
+  <string name="setup_btn_connect">Повежи се</string>
   <string name="uploader_btn_upload_text">Отпреми</string>
+  <string name="uploader_top_message">Изаберите фасциклу отпремања:</string>
   <string name="uploader_wrn_no_account_title">Нема налога</string>
+  <string name="uploader_wrn_no_account_text">Нема %1$s налога на вашем уређају. Прво подесите налог.</string>
   <string name="uploader_wrn_no_account_setup_btn_text">Подеси</string>
-  <string name="uploader_wrn_no_account_quit_btn_text">Ð\98заÑ\92и</string>
+  <string name="uploader_wrn_no_account_quit_btn_text">Ð\9dапÑ\83Ñ\81Ñ\82и</string>
   <string name="uploader_wrn_no_content_title">Нема садржаја за отпремање</string>
-  <string name="uploader_wrn_no_content_text">Садржај није примљен. Нема ништа да се отпреми.</string>
+  <string name="uploader_wrn_no_content_text">Садржај није примљен. Нема шта да се отпреми.</string>
   <string name="uploader_info_uploading">Отпремање</string>
-  <string name="file_list_seconds_ago">пÑ\80е Ð½ÐµÐºÐ¾Ð»Ð¸ÐºÐ¾ секунди</string>
+  <string name="file_list_seconds_ago">пÑ\80е Ð¿Ð°Ñ\80 секунди</string>
   <string name="file_list_empty">Овде нема ничег. Отпремите нешто!</string>
-  <string name="filedetails_select_file">Додирните датотеку ради приказа додатних информација.</string>
+  <string name="file_list_loading">Учитавам</string>
+  <string name="local_file_list_empty">Нема фајлова у овој фасцикли.</string>
+  <string name="filedetails_select_file">Тапните на фајл ради приказа додатних информација.</string>
   <string name="filedetails_size">Величина:</string>
   <string name="filedetails_type">Врста:</string>
-  <string name="filedetails_created">Направљено:</string>
-  <string name="filedetails_modified">Измењено:</string>
+  <string name="filedetails_created">Направљен:</string>
+  <string name="filedetails_modified">Измењен:</string>
   <string name="filedetails_download">Преузми</string>
-  <string name="filedetails_sync_file">Освежи датотеку</string>
+  <string name="filedetails_sync_file">Освежи фајл</string>
+  <string name="filedetails_renamed_in_upload_msg">Фајл је преименован у %1$s током отпремања</string>
+  <string name="action_share_file">Веза дељења</string>
+  <string name="action_unshare_file">Не дели везом</string>
   <string name="common_yes">Да</string>
   <string name="common_no">Не</string>
   <string name="common_ok">У реду</string>
-  <string name="common_cancel_download">Обустави преузимање</string>
-  <string name="common_cancel_upload">Ð\9fÑ\80екини Ñ\81лање</string>
+  <string name="common_cancel_download">Откажи преузимање</string>
+  <string name="common_cancel_upload">Ð\9eÑ\82кажи Ð¾Ñ\82пÑ\80емање</string>
   <string name="common_cancel">Откажи</string>
   <string name="common_save_exit">Сачувај и изађи</string>
   <string name="common_error">Грешка</string>
+  <string name="common_loading">Учитавам...</string>
+  <string name="common_error_unknown">Непозната грешка</string>
   <string name="about_title">О програму</string>
   <string name="change_password">Измени лозинку</string>
   <string name="delete_account">Обриши налог</string>
   <string name="create_account">Отвори налог</string>
   <string name="upload_chooser_title">Отпреми из…</string>
+  <string name="uploader_info_dirname">Назив фасцикле</string>
   <string name="uploader_upload_in_progress_ticker">Отпремам…</string>
   <string name="uploader_upload_in_progress_content">%1$d%% Отпремам %2$s</string>
   <string name="uploader_upload_succeeded_ticker">Отпремање је успело</string>
+  <string name="uploader_upload_succeeded_content_single">%1$s је успешно отпремљен</string>
   <string name="uploader_upload_failed_ticker">Отпремање није успело</string>
-  <string name="uploader_upload_failed_content_single">Не могу да довршим отпремање датотеке %1$s</string>
+  <string name="uploader_upload_failed_content_single">Не могу да довршим отпремање %1$s</string>
+  <string name="uploader_upload_failed_credentials_error">Отпремање неуспешно. Поново се пријавите.</string>
   <string name="downloader_download_in_progress_ticker">Преузимам…</string>
   <string name="downloader_download_in_progress_content">%1$d%% Преузимам %2$s</string>
   <string name="downloader_download_succeeded_ticker">Преузимање успешно</string>
   <string name="downloader_download_succeeded_content">%1$s је успешно преузет</string>
   <string name="downloader_download_failed_ticker">Преузимање није успело</string>
-  <string name="downloader_download_failed_content">Не могу да довршим преузимање датотеке %1$s</string>
+  <string name="downloader_download_failed_content">Не могу да довршим преузимање %1$s</string>
   <string name="downloader_not_downloaded_yet">Још увек није преузето</string>
-  <string name="common_choose_account">Изабери налог</string>
+  <string name="downloader_download_failed_credentials_error">Преузимање неуспешно. Пријавите се поново</string>
+  <string name="common_choose_account">Изаберите налог</string>
   <string name="sync_fail_ticker">Синхронизовање није успело</string>
-  <string name="sync_fail_content">Не могу да довршим синхронизацију датотеке %1$s</string>
-  <string name="foreign_files_success">Све датотеке су померене</string>
-  <string name="foreign_files_fail">Неке датотеке нису могле бити померене</string>
-  <string name="pincode_enter_pin_code">Унесите PIN апликације</string>
-  <string name="pincode_configure_your_pin_explanation">Са сваким покретањем апликације мораћете да унесете PIN</string>
+  <string name="sync_fail_ticker_unauthorized">Синхронизовање неуспешно. Пријавите се поново</string>
+  <string name="sync_fail_content">Не могу да довршим синхронизацију %1$s</string>
+  <string name="sync_fail_content_unauthorized">Неисправна лозинка за %1$s</string>
+  <string name="sync_conflicts_in_favourites_ticker">Постоје сукоби</string>
+  <string name="sync_foreign_files_forgotten_explanation">Од верзије 1.3.16, фајлови отпремљени са уређаја се копирају у локалну фасциклу %1$s да би се спречио губитак података када се исти фајл синхронизује са више налога.\n\nЗбог ове измене, сви фајлови отпремљени са претходним верзијама ове апликације се копирају у фасциклу %2$s. Међутим, грешка је онемогућила довршавање ове радње током синхронизације налога. Можете или оставити фајлове како јесу и уклонити линк до %3$s или преместити фајлове у фасциклу %1$s и задржати везу до %4$s.\n\nИспод су наведени локални фајлови и удаљени фајлови у %5$s са којима су повезани.</string>
+  <string name="sync_current_folder_was_removed">Фасцикла %1$s више не постоји</string>
+  <string name="foreign_files_move">Премести све</string>
+  <string name="foreign_files_success">Сви фајлови су премештени</string>
+  <string name="foreign_files_fail">Неки фајлови нису могли бити премештени</string>
+  <string name="foreign_files_local_text">Локално: %1$s</string>
+  <string name="foreign_files_remote_text">Удаљено: %1$s</string>
+  <string name="upload_query_move_foreign_files">Нема довољно простора да би се изабрани фајлови копирали у фасциклу %1$s. Желите ли да их преместите? </string>
+  <string name="pincode_enter_pin_code">Унесите ПИБ апликације</string>
+  <string name="pincode_configure_your_pin">Унесите ПИБ за апликацију</string>
+  <string name="pincode_configure_your_pin_explanation">Са сваким покретањем апликације мораћете да унесете ПИБ</string>
+  <string name="pincode_reenter_your_pincode">Унесите ПИБ поново</string>
+  <string name="pincode_remove_your_pincode">Уклоните ПИБ апликације</string>
+  <string name="pincode_mismatch">Бројеви се не поклапају</string>
+  <string name="pincode_wrong">Неисправан ПИБ</string>
+  <string name="pincode_removed">ПИБ је уклоњен</string>
+  <string name="pincode_stored">ПИБ је упамћен</string>
+  <string name="media_notif_ticker">%1$s музички плејер</string>
+  <string name="media_state_playing">%1$s (пуштам)</string>
+  <string name="media_state_loading">%1$s (учитавам)</string>
+  <string name="media_event_done">%1$s пуштање завршено</string>
+  <string name="media_err_nothing_to_play">Нема медијских фајлова</string>
+  <string name="media_err_no_account">Није наведен налог</string>
+  <string name="media_err_not_in_owncloud">Фајл није у исправном налогу</string>
+  <string name="media_err_unsupported">Неподржан кодек</string>
+  <string name="media_err_io">Медијски фајл се не може читати</string>
+  <string name="media_err_malformed">Медијски фајл није исправно кодиран</string>
+  <string name="media_err_timeout">Време истекло у покушавању пуштања</string>
+  <string name="media_err_invalid_progressive_playback">Медијски фајл се не може пустити</string>
+  <string name="media_err_unknown">Медијски фајл се не може пустити са фабричким плејером</string>
+  <string name="media_err_security_ex">Безбедносна грешка при покушају пуштања %1$s</string>
+  <string name="media_err_io_ex">Улазна грешка при покушају пуштања %1$s</string>
+  <string name="media_err_unexpected">Неочекивана грешка при покушају пуштања %1$s</string>
+  <string name="media_rewind_description">Уназад</string>
+  <string name="media_play_pause_description">Пуштање-пауза</string>
+  <string name="media_forward_description">Унапред</string>
+  <string name="auth_getting_authorization">Тражим ауторизацију...</string>
+  <string name="auth_trying_to_login">Покушавам пријављивање...</string>
   <string name="auth_no_net_conn_title">Нема мрежне везе</string>
   <string name="auth_nossl_plain_ok_title">Безбедна веза није доступна.</string>
   <string name="auth_connection_established">Веза је успостављена</string>
-  <string name="auth_unknown_error_title">Дошло је до непознате грешке.</string>
+  <string name="auth_testing_connection">Тестирам везу...</string>
+  <string name="auth_not_configured_title">Лоше подешавање сервера</string>
+  <string name="auth_account_not_new">Налог са истим корисником и сервером већ постоји на уређају</string>
+  <string name="auth_account_not_the_same">Унесени корисник се не поклапа са корисником овог налога</string>
+  <string name="auth_unknown_error_title">Дошло је до непознате грешке!</string>
   <string name="auth_unknown_host_title">Не могу да пронађем домаћина</string>
   <string name="auth_incorrect_path_title">Не могу да пронађем примерак сервера</string>
   <string name="auth_timeout_title">Серверу је требало предуго да се одазове</string>
   <string name="auth_incorrect_address_title">Погрешно уобличена адреса</string>
-  <string name="auth_ssl_general_error_title">Покретање SSL-а није успело</string>
+  <string name="auth_ssl_general_error_title">ССЛ иницијализација није успела</string>
+  <string name="auth_ssl_unverified_server_title">Не могу да проверим ССЛ идентитет сервера</string>
+  <string name="auth_bad_oc_version_title">Непозната верзија сервера</string>
   <string name="auth_wrong_connection_title">Не могу да успоставим везу</string>
   <string name="auth_secure_connection">Безбедна веза је успостављена</string>
-  <string name="fd_keep_in_sync">Редовно ажурирај датотеку</string>
+  <string name="auth_unauthorized">Погрешно име или лозинка</string>
+  <string name="auth_oauth_error">Неуспешна ауторизација</string>
+  <string name="auth_oauth_error_access_denied">Сервер ауторизације је одбио приступ</string>
+  <string name="auth_wtf_reenter_URL">Неочекивано стање. Унесите поново адресу сервера</string>
+  <string name="auth_expired_oauth_token_toast">Ауторизација је истекла. Урадите је поново</string>
+  <string name="auth_expired_basic_auth_toast">Унесите тренутну лозинку</string>
+  <string name="auth_expired_saml_sso_token_toast">Сесија је истекла. Повежите се поново</string>
+  <string name="auth_connecting_auth_server">Повезујем се на сервер аутентификације...</string>
+  <string name="auth_unsupported_auth_method">Сервер не подржава овај начин аутентификације</string>
+  <string name="auth_unsupported_multiaccount">%1$s не подржава вишеструке налоге</string>
+  <string name="auth_fail_get_user_name">Сервер не враћа исправан ИД корисника. Контактирајте администратора
+       </string>
+  <string name="auth_can_not_auth_against_server">Не могу да аутентификујем са овим сервером</string>
+  <string name="auth_account_does_not_exist">Не постоји налог на уређају</string>
+  <string name="fd_keep_in_sync">Редовно ажурирај фајл</string>
   <string name="common_rename">Преименуј</string>
   <string name="common_remove">Уклони</string>
+  <string name="confirmation_remove_alert">Желите да уклоните %1$s?</string>
+  <string name="confirmation_remove_folder_alert">Желите да уклоните %1$s и њен садржај?</string>
   <string name="confirmation_remove_local">Само локално</string>
+  <string name="confirmation_remove_folder_local">Само локални садржај</string>
   <string name="confirmation_remove_remote">Уклони са сервера</string>
   <string name="confirmation_remove_remote_and_local">Удаљено и локално</string>
-  <string name="rename_dialog_title">Унесите ново име</string>
+  <string name="remove_success_msg">Уклањање успешно</string>
+  <string name="remove_fail_msg">Уклањање неуспешно</string>
+  <string name="rename_dialog_title">Унесите нов назив</string>
+  <string name="rename_local_fail_msg">Локална копија се не може преименовати. Покушајте други назив</string>
   <string name="rename_server_fail_msg">Не могу да довршим преименовање</string>
-  <string name="sync_file_fail_msg">Удаљена датотека се не може проверити</string>
+  <string name="sync_file_fail_msg">Удаљени фајл се не може проверити</string>
+  <string name="sync_file_nothing_to_do_msg">Садржај је већ синхронизован</string>
+  <string name="create_dir_fail_msg">Фасцикла се не може направити</string>
+  <string name="filename_forbidden_characters">Забрањени знакови: / \\ &lt; &gt; : \" | ? *</string>
+  <string name="filename_empty">Назив фајла не може бити празан</string>
   <string name="wait_a_moment">Сачекајте тренутак</string>
-  <string name="filedisplay_no_file_selected">Нисте изабрали датотеку</string>
+  <string name="filedisplay_unexpected_bad_get_content">Неочекивани проблем. Изаберите фајл другом апликацијом</string>
+  <string name="filedisplay_no_file_selected">Нисте изабрали фајл</string>
+  <string name="activity_chooser_title">Пошаљи везу ...</string>
+  <string name="oauth_check_onoff">Пријави се помоћу „oAuth2“</string>
+  <string name="oauth_login_connection">Повезујем се на „oAuth2“ сервер...</string>
   <string name="ssl_validator_header">Не могу да проверим идентитет сајта</string>
-  <string name="ssl_validator_reason_cert_not_trusted">â\80\93 Ð¡ÐµÑ\80Ñ\82иÑ\84икаÑ\82 Ñ\81еÑ\80веÑ\80а Ð½Ð¸Ñ\98е Ð¿Ð¾Ð²ÐµÑ\80Ñ\99ив</string>
+  <string name="ssl_validator_reason_cert_not_trusted">â\80\93 Ð¡ÐµÑ\80Ñ\82иÑ\84икаÑ\82 Ñ\81еÑ\80веÑ\80а Ð½Ð¸Ñ\98е Ð¾Ð´ Ð¿Ð¾Ð²ÐµÑ\80еÑ\9aа</string>
   <string name="ssl_validator_reason_cert_expired">– Сертификат сервера је истекао</string>
+  <string name="ssl_validator_reason_cert_not_yet_valid">- Датуми важења сертификата су у будућности</string>
   <string name="ssl_validator_reason_hostname_not_verified">– Адреса се не поклапа са именом домаћина у сертификату</string>
-  <string name="ssl_validator_question">Ð\96елиÑ\82е Ð»Ð¸ Ð¸Ð¿Ð°Ðº Ð´Ð° Ð¾Ð·Ð½Ð°Ñ\87иÑ\82е Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82 ÐºÐ°Ð¾ Ð¿Ð¾Ð²ÐµÑ\80Ñ\99ив?</string>
+  <string name="ssl_validator_question">Ð\96елиÑ\82е Ð»Ð¸ Ð¸Ð¿Ð°Ðº Ð´Ð° Ð²ÐµÑ\80Ñ\83Ñ\98еÑ\82е Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82Ñ\83?</string>
   <string name="ssl_validator_not_saved">Не могу да сачувам сертификат</string>
   <string name="ssl_validator_btn_details_see">Подаци</string>
   <string name="ssl_validator_btn_details_hide">Сакриј</string>
   <string name="ssl_validator_label_subject">Издато за:</string>
-  <string name="ssl_validator_label_issuer">Ð\98здао/ла:</string>
+  <string name="ssl_validator_label_issuer">Ð\98здаваÑ\87:</string>
   <string name="ssl_validator_label_CN">Уобичајено име:</string>
   <string name="ssl_validator_label_O">Организација:</string>
   <string name="ssl_validator_label_OU">Организациона јединица:</string>
-  <string name="ssl_validator_label_C">Ð\97емÑ\99а:</string>
-  <string name="ssl_validator_label_ST">Ð\94Ñ\80жава:</string>
+  <string name="ssl_validator_label_C">Ð\94Ñ\80жава:</string>
+  <string name="ssl_validator_label_ST">Ð\9fокÑ\80аÑ\98ина:</string>
   <string name="ssl_validator_label_L">Локација:</string>
   <string name="ssl_validator_label_validity">Ваљаност:</string>
   <string name="ssl_validator_label_validity_from">Од:</string>
   <string name="ssl_validator_label_validity_to">За:</string>
   <string name="ssl_validator_label_signature">Потпис:</string>
   <string name="ssl_validator_label_signature_algorithm">Алгоритам:</string>
+  <string name="ssl_validator_null_cert">Сертификат се не може приказати.</string>
+  <string name="ssl_validator_no_info_about_error">- Нема података о грешци</string>
+  <string name="placeholder_sentence">Ово је местодржач</string>
+  <string name="placeholder_filename">чувамместо.txt</string>
+  <string name="placeholder_filetype">ПНГ слика</string>
+  <string name="placeholder_filesize">389 KB</string>
+  <string name="placeholder_timestamp">2012/05/18 12:23 ПоП</string>
+  <string name="placeholder_media_time">12:23:45</string>
   <string name="instant_upload_on_wifi">Отпремај слике само путем бежичне мреже</string>
+  <string name="instant_video_upload_on_wifi">Отпремај видео само путем бежичне мреже</string>
   <string name="conflict_title">Ажурирај сукоб</string>
+  <string name="conflict_message">Удаљени фајл %s није синхронизован са локалним. Ако наставите, заменићете фајл на серверу.</string>
+  <string name="conflict_keep_both">Задржи оба</string>
+  <string name="conflict_overwrite">Пребриши</string>
+  <string name="conflict_dont_upload">Не отпремај</string>
+  <string name="preview_image_description">Преглед слике</string>
+  <string name="preview_image_error_unknown_format">Слика се не може приказати</string>
+  <string name="error__upload__local_file_not_copied">%1$s се не може копирати у локалну фасциклу %2$s</string>
+  <string name="prefs_instant_upload_path_title">Путања отпремања</string>
+  <string name="share_link_no_support_share_api">Дељење није укључено на вашем серверу. Контактирајте
+               администратора.</string>
+  <string name="share_link_file_no_exist">Не могу да делим. Проверите да ли фајл постоји</string>
+  <string name="share_link_file_error">Дошло је до грешке приликом покушаја дељења овог фајла или фасцикле</string>
+  <string name="unshare_link_file_no_exist">Не могу да прекинем дељење. Проверите да ли фајл постоји</string>
+  <string name="unshare_link_file_error">Дошло је до грешке приликом покушаја укидања дељења овог фајла или фасцикле</string>
+  <string name="share_link_password_title">Унесите лозинку</string>
+  <string name="share_link_empty_password">Морате унети лозинку</string>
   <string name="activity_chooser_send_file_title">Пошаљи</string>
+  <string name="copy_link">Копирај везу</string>
+  <string name="clipboard_text_copied">Копирано у клипборд</string>
+  <string name="error_cant_bind_to_operations_service">Критична грешка: не могу да радим</string>
+  <string name="network_error_socket_exception">Дошло је до грешке при повезивању са сервером.</string>
+  <string name="network_error_socket_timeout_exception">Дошло је до грешке при чекању на сервер. Радња није могла бити урађена</string>
+  <string name="network_error_connect_timeout_exception">Дошло је до грешке при чекању на сервер. Радња није могла бити урађена</string>
+  <string name="network_host_not_available">Радња није могла бити довршена. Сервер је недоступан</string>
   <string name="empty"></string>
+  <string name="forbidden_permissions">Немате дозволу %s</string>
+  <string name="forbidden_permissions_rename">да преименујете овај фајл</string>
+  <string name="forbidden_permissions_delete">да обришете овај фајл</string>
+  <string name="share_link_forbidden_permissions">да делите овај фајл</string>
+  <string name="unshare_link_forbidden_permissions">да укинете дељење овог фајла</string>
+  <string name="forbidden_permissions_create">да направите фајл</string>
+  <string name="uploader_upload_forbidden_permissions">да отпремате у ову фасциклу</string>
+  <string name="downloader_download_file_not_found">Фајл није више доступан на серверу</string>
   <string name="prefs_category_accounts">Налози</string>
+  <string name="prefs_add_account">Додај налог</string>
+  <string name="auth_redirect_non_secure_connection_title">Безбедна веза је преусмерена на небезбедну руту</string>
+  <string name="actionbar_logger">Записници</string>
+  <string name="log_send_history_button">Историјат слања</string>
+  <string name="log_send_no_mail_app">Нема начина за слање записника. Инсталирајте апликацију е-поште!</string>
+  <string name="log_send_mail_subject">Записници %1$s Андроид апликације</string>
+  <string name="log_progress_dialog_text">Учитавам податке...</string>
+  <string name="saml_authentication_required_text">Неопходна провера идентитета</string>
+  <string name="saml_authentication_wrong_pass">Погрешна лозинка</string>
+  <string name="actionbar_move">Премести</string>
+  <string name="file_list_empty_moving">Овде нема ничега. Можете додати фасциклу!</string>
   <string name="folder_picker_choose_button_text">Одабери</string>
+  <string name="move_file_not_found">Не могу да преместим. Проверите да ли фајл постоји</string>
+  <string name="move_file_invalid_into_descendent">Није могуће преместити фасциклу у њену потфасциклу</string>
+  <string name="move_file_invalid_overwrite">Фајл већ постоји у одредишној фасцикли</string>
+  <string name="move_file_error">Дошло је до грешке при премештању фајла или фасцикле</string>
+  <string name="forbidden_permissions_move">да преместите овај фајл</string>
+  <string name="prefs_category_instant_uploading">Тренутна отпремања</string>
   <string name="prefs_category_security">Безбедност</string>
+  <string name="prefs_instant_video_upload_path_title">Путања отпремања видеа</string>
+  <string name="download_folder_failed_content">Преузимање фасцикле %1$s не може бити довршено</string>
+  <string name="subject_token">%1$s подели „%2$s“ са вама</string>
 </resources>
index 254ed65..f44afac 100644 (file)
   <string name="prefs_category_instant_uploading">Direktuppladning</string>
   <string name="prefs_category_security">Säkerhet</string>
   <string name="prefs_instant_video_upload_path_title">Uppladdnings-sökväg för video</string>
-  <string name="shared_subject_header">delad</string>
-  <string name="with_you_subject_header">med dig</string>
-  <string name="subject_token">%1$s %2$s &gt;&gt;%3$s&lt;&lt; %4$s</string>
 </resources>
index 8a0664e..97c73a5 100644 (file)
@@ -64,9 +64,9 @@
   <string name="file_list_loading">Yükleniyor...</string>
   <string name="local_file_list_empty">Bu klasörde dosya yok.</string>
   <string name="file_list_folder">klasör</string>
-  <string name="file_list_folders">klasörler</string>
+  <string name="file_list_folders">klasör</string>
   <string name="file_list_file">dosya</string>
-  <string name="file_list_files">dosyalar</string>
+  <string name="file_list_files">dosya</string>
   <string name="filedetails_select_file">Ek bilgileri görmek için dosyaya dokunun.</string>
   <string name="filedetails_size">Boyut:</string>
   <string name="filedetails_type">Tür:</string>
   <string name="auth_fail_get_user_name">Sunucunuz geçerli bir kullanıcı kimliği döndürmüyor, lütfen yöneticinizle iletişime geçin
         </string>
   <string name="auth_can_not_auth_against_server">Bu sunucuya karşı kimlik doğrulama yapılamaz</string>
+  <string name="auth_account_does_not_exist">Hesap henüz cihazda mevcut değil</string>
   <string name="fd_keep_in_sync">Dosyayı güncel tut</string>
   <string name="common_rename">Yeniden adlandır</string>
   <string name="common_remove">Kaldır</string>
   <string name="share_link_file_error">Bu dosya veya klasörü paylaşmaya çalışılırken bir hata oluştu</string>
   <string name="unshare_link_file_no_exist">Paylaşımı kaldırma başarısız. Lütfen dosyanın mevcut olup olmadığını denetleyin</string>
   <string name="unshare_link_file_error">Bu dosya veya klasör paylaşımı kaldırılmaya çalışılırken bir hata oluştu</string>
+  <string name="share_link_password_title">Bir parola girin</string>
+  <string name="share_link_empty_password">Bir parola girmelisiniz</string>
   <string name="activity_chooser_send_file_title">Gönder</string>
   <string name="copy_link">Bağlantıyı kopyala</string>
   <string name="clipboard_text_copied">Panoya kopyalandı</string>
   <string name="prefs_category_security">Güvenlik</string>
   <string name="prefs_instant_video_upload_path_title">Video Yükleme Yolu</string>
   <string name="download_folder_failed_content">%1$s klasörün indirilmesi tamamlanamadı</string>
-  <string name="shared_subject_header">paylaşılan</string>
-  <string name="with_you_subject_header">sizinle</string>
-  <string name="subject_token">%1$s %2$s &gt;&gt;%3$s&lt;&lt; %4$s</string>
+  <string name="subject_token">%1$s sizinle \"%2$s\" paylaşımını yaptı</string>
 </resources>
index abee26e..12a5492 100644 (file)
@@ -44,5 +44,4 @@
   <string name="empty"></string>
   <string name="prefs_category_accounts">ھېساباتلار</string>
   <string name="prefs_category_security">بىخەتەرلىك</string>
-  <string name="shared_subject_header">ھەمبەھىرلەنگەن</string>
 </resources>
index e57daea..64c57d3 100644 (file)
   <string name="uploader_upload_failed_ticker">Помилка завантаження</string>
   <string name="uploader_upload_failed_content_single">Завантаження %1$s не може завершитись</string>
   <string name="uploader_upload_failed_credentials_error">Завантажити не вдалося, необхідно повторити вхід</string>
-  <string name="downloader_download_in_progress_ticker">Ð\97качування …</string>
+  <string name="downloader_download_in_progress_ticker">Скачування …</string>
   <string name="downloader_download_in_progress_content">%1$d%% Зкачування %2$s</string>
   <string name="downloader_download_succeeded_ticker">Успішно зкачано</string>
   <string name="downloader_download_succeeded_content">%1$s успішно завантажено</string>
   <string name="prefs_category_instant_uploading">Миттєво завантаження</string>
   <string name="prefs_category_security">Безпека</string>
   <string name="prefs_instant_video_upload_path_title">Шлях завантаження відео</string>
-  <string name="shared_subject_header">спільне</string>
-  <string name="with_you_subject_header">з тобою</string>
-  <string name="subject_token">%1$s %2$s &gt;&gt;%3$s&lt;&lt; %4$s</string>
+  <string name="download_folder_failed_content">Скачування теки %1$s не може бути завершено</string>
 </resources>
index 22142ac..28123e0 100644 (file)
   <string name="prefs_category_instant_uploading">即时上传</string>
   <string name="prefs_category_security">安全</string>
   <string name="prefs_instant_video_upload_path_title">视频上传路径</string>
-  <string name="shared_subject_header">分享</string>
+  <string name="download_folder_failed_content">%1$s 文件夹的下载无法完成</string>
 </resources>
index 641adaf..4659d43 100644 (file)
   <string name="prefs_category_instant_uploading">即時上傳</string>
   <string name="prefs_category_security">安全性</string>
   <string name="prefs_instant_video_upload_path_title">影片上傳路徑</string>
-  <string name="shared_subject_header">以分享的</string>
-  <string name="with_you_subject_header">與你</string>
-  <string name="subject_token">%1$s %2$s &gt;&gt;%3$s&lt;&lt; %4$s</string>
+  <string name="download_folder_failed_content">%1$s 目錄的下載未完成</string>
 </resources>
index 1c8d68c..c2ca673 100644 (file)
@@ -2,7 +2,7 @@
 <!--
   ownCloud Android client application
 
-  Copyright (C) 2012-2013 ownCloud Inc.
+  Copyright (C) 2015 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,
index 2b1fec9..6aeb6ac 100644 (file)
@@ -3,7 +3,7 @@
   ownCloud Android client application
 
   Copyright (C) 2012  Bartek Przybylski
-  Copyright (C) 2012-2013 ownCloud Inc.
+  Copyright (C) 2015 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,
@@ -22,5 +22,7 @@
     <color name="filelist_icon_backgorund">#DDDDDD</color>
     <color name="owncloud_blue_bright">#00ddff</color>
     <color name="list_item_lastmod_and_filesize_text">#989898</color>
+    <color name="textColor">#303030</color>
+    <color name="list_divider_background">#fff0f0f0</color>
     
 </resources>
\ No newline at end of file
index d433cba..955f87e 100644 (file)
@@ -18,4 +18,5 @@
 -->
 <resources>
        <dimen name="file_icon_size">32dp</dimen>
+    <dimen name="file_icon_size_grid">128dp</dimen>
 </resources>
index d04bd1b..da18ec5 100644 (file)
        <string name="auth_fail_get_user_name">Your server is not returning a correct user id, please contact an administrator
        </string>
        <string name="auth_can_not_auth_against_server">Cannot authenticate against this server</string>
+    <string name="auth_account_does_not_exist">Account does not exist in the device yet</string>
     
     <string name="fd_keep_in_sync">Keep file up to date</string>
     <string name="common_rename">Rename</string>
        <string name="share_link_file_error">An error occurred while trying to share this file or folder</string>
        <string name="unshare_link_file_no_exist">Unable to unshare. Please check whether the file exists</string>
        <string name="unshare_link_file_error">An error occurred while trying to unshare this file or folder</string>
+    <string name="share_link_password_title">Enter a password</string>
+    <string name="share_link_empty_password">You must enter a password</string>
 
        <string name="activity_chooser_send_file_title">Send</string>
 
        <string name="prefs_instant_video_upload_path_title">Upload Video Path</string>
     <string name="download_folder_failed_content">Download of %1$s folder could not be completed</string>
 
-       <string name="shared_subject_header">shared</string>
-       <string name="with_you_subject_header">with you</string>
-       <string name="subject_token">%1$s %2$s &gt;&gt;%3$s&lt;&lt; %4$s</string>
+       <string name="subject_token">%1$s shared \"%2$s\" with you</string>
 
 </resources>
index c65cbad..5996281 100644 (file)
@@ -3,7 +3,7 @@
   ownCloud Android client application
 
   Copyright (C) 2012  Bartek Przybylski
-  Copyright (C) 2012-2013 ownCloud Inc.
+  Copyright (C) 2015 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,
index eb25005..d0e8244 100644 (file)
@@ -3,7 +3,7 @@
   ownCloud Android client application
 
   Copyright (C) 2012  Bartek Przybylski
-  Copyright (C) 2012-2013 ownCloud Inc.
+  Copyright (C) 2015 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,
index b674cbc..ac36984 100644 (file)
@@ -3,7 +3,7 @@
   ownCloud Android client application
 
   Copyright (C) 2012  Bartek Przybylski
-  Copyright (C) 2012-2013 ownCloud Inc.
+  Copyright (C) 2015 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,
index 8c8d8b3..805b53e 100644 (file)
@@ -3,7 +3,7 @@
   ownCloud Android client application
 
   Copyright (C) 2012  Bartek Przybylski
-  Copyright (C) 2012-2013 ownCloud Inc.
+  Copyright (C) 2015 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,
index c2a4c68..2d819f4 100644 (file)
@@ -1,5 +1,9 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2013 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   @author masensio
+ *   @author David A. Velasco
+ *   Copyright (C) 2015 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,
@@ -28,9 +32,6 @@ import com.owncloud.android.lib.common.utils.Log_OC;
  * 
  * Contains methods to build the "static" strings. These strings were before constants in different
  * classes
- * 
- * @author masensio
- * @author David A. Velasco
  */
 public class MainApp extends Application {
     
index 1d52fd0..a40b7dd 100644 (file)
@@ -1,6 +1,9 @@
-/* ownCloud Android client application
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
  *   Copyright (C) 2012  Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
+ *   Copyright (C) 2015 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,
@@ -38,9 +41,7 @@ import com.owncloud.android.lib.common.utils.Log_OC;
  *  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
+ *  TODO - review completeness
  */
 public class AccountAuthenticator extends AbstractAccountAuthenticator {
     
@@ -122,39 +123,39 @@ public class AccountAuthenticator extends AbstractAccountAuthenticator {
         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 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;
+    }
+
     /**
      * {@inheritDoc}
      */
@@ -253,69 +254,69 @@ public class AccountAuthenticator extends AbstractAccountAuthenticator {
         }
     }
 
-    private void validateAuthTokenType(String authTokenType)\r
-            throws UnsupportedAuthTokenTypeException {\r
-        if (!authTokenType.equals(MainApp.getAuthTokenType()) &&\r
-            !authTokenType.equals(AccountTypeUtils.getAuthTokenTypePass(MainApp.getAccountType())) &&\r
-            !authTokenType.equals(AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType())) &&\r
+    private void validateAuthTokenType(String authTokenType)
+            throws UnsupportedAuthTokenTypeException {
+        if (!authTokenType.equals(MainApp.getAuthTokenType()) &&
+            !authTokenType.equals(AccountTypeUtils.getAuthTokenTypePass(MainApp.getAccountType())) &&
+            !authTokenType.equals(AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType())) &&
             !authTokenType.equals(AccountTypeUtils.getAuthTokenTypeRefreshToken(MainApp.getAccountType())) &&
-            !authTokenType.equals(AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()))) {\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
+            !authTokenType.equals(AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()))) {
+            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;
+
+    }
+}
index c479cea..915b015 100644 (file)
@@ -1,6 +1,8 @@
-/* ownCloud Android client application
+/**
+ *   ownCloud Android client application
+ *
  *   Copyright (C) 2011  Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
+ *   Copyright (C) 2015 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,
index dc02344..bd3a8e7 100644 (file)
@@ -1,6 +1,8 @@
-/* ownCloud Android client application\r
+/**\r
+ *   ownCloud Android client application\r
+ *\r
  *   Copyright (C) 2012  Bartek Przybylski\r
- *   Copyright (C) 2012-2013 ownCloud Inc.\r
+ *   Copyright (C) 2015 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
index df4e21b..1e4e8b4 100644 (file)
@@ -1,6 +1,11 @@
-/* ownCloud Android client application\r
+/**\r
+ *   ownCloud Android client application\r
+ *\r
+ *   @author Bartek Przybylski\r
+ *   @author David A. Velasco\r
+ *   @author masensio\r
  *   Copyright (C) 2012  Bartek Przybylski\r
- *   Copyright (C) 2012-2014 ownCloud Inc.\r
+ *   Copyright (C) 2015 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
@@ -64,7 +69,10 @@ import com.actionbarsherlock.app.SherlockDialogFragment;
 import com.owncloud.android.MainApp;\r
 import com.owncloud.android.R;\r
 import com.owncloud.android.authentication.SsoWebViewClient.SsoWebViewClientListener;\r
+import com.owncloud.android.lib.common.OwnCloudCredentials;\r
+import com.owncloud.android.lib.common.OwnCloudCredentialsFactory;\r
 import com.owncloud.android.lib.common.accounts.AccountTypeUtils;\r
+import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException;\r
 import com.owncloud.android.lib.common.accounts.AccountUtils.Constants;\r
 import com.owncloud.android.lib.common.network.CertificateCombinedException;\r
 import com.owncloud.android.lib.common.operations.OnRemoteOperationListener;\r
@@ -72,7 +80,6 @@ import com.owncloud.android.lib.common.operations.RemoteOperation;
 import com.owncloud.android.lib.common.operations.RemoteOperationResult;\r
 import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;\r
 import com.owncloud.android.lib.common.utils.Log_OC;\r
-import com.owncloud.android.lib.resources.files.ExistenceCheckRemoteOperation;\r
 import com.owncloud.android.lib.resources.status.OwnCloudVersion;\r
 import com.owncloud.android.lib.resources.users.GetRemoteUserNameOperation;\r
 import com.owncloud.android.operations.DetectAuthenticationMethodOperation.AuthenticationMethod;\r
@@ -89,14 +96,11 @@ import com.owncloud.android.utils.DisplayUtils;
 \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
- * @author masensio\r
  */\r
 public class AuthenticatorActivity extends AccountAuthenticatorActivity\r
-implements  OnRemoteOperationListener, OnFocusChangeListener, OnEditorActionListener, \r
-SsoWebViewClientListener, OnSslUntrustedCertListener {\r
+        implements  OnRemoteOperationListener, OnFocusChangeListener, OnEditorActionListener,\r
+        SsoWebViewClientListener, OnSslUntrustedCertListener,\r
+        AuthenticatorAsyncTask.OnAuthenticatorTaskListener {\r
 \r
     private static final String TAG = AuthenticatorActivity.class.getSimpleName();\r
 \r
@@ -132,6 +136,9 @@ SsoWebViewClientListener, OnSslUntrustedCertListener {
     private static final String CREDENTIALS_DIALOG_TAG = "CREDENTIALS_DIALOG";\r
     private static final String KEY_AUTH_IS_FIRST_ATTEMPT_TAG = "KEY_AUTH_IS_FIRST_ATTEMPT";\r
 \r
+    private static final String KEY_USERNAME = "USERNAME";\r
+    private static final String KEY_PASSWORD = "PASSWORD";\r
+    private static final String KEY_ASYNC_TASK_IN_PROGRESS = "AUTH_IN_PROGRESS";\r
     \r
     /// parameters from EXTRAs in starter Intent\r
     private byte mAction;\r
@@ -175,14 +182,19 @@ SsoWebViewClientListener, OnSslUntrustedCertListener {
     private int mAuthStatusText = 0, mAuthStatusIcon = 0;\r
     \r
     private String mAuthToken = "";\r
+    private AuthenticatorAsyncTask mAsyncTask;\r
 \r
     private boolean mIsFirstAuthAttempt;\r
-\r
     \r
     /// Identifier of operation in progress which result shouldn't be lost \r
     private long mWaitingForOpId = Long.MAX_VALUE;\r
 \r
-    \r
+    private final String BASIC_TOKEN_TYPE = AccountTypeUtils.getAuthTokenTypePass(MainApp.getAccountType());\r
+    private final String OAUTH_TOKEN_TYPE = AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType());\r
+    private final String SAML_TOKEN_TYPE =\r
+            AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType());\r
+\r
+\r
     /**\r
      * {@inheritDoc}\r
      * \r
@@ -227,7 +239,7 @@ SsoWebViewClientListener, OnSslUntrustedCertListener {
         setContentView(R.layout.account_setup);\r
         \r
         /// initialize general UI elements\r
-        initOverallUi(savedInstanceState);\r
+        initOverallUi();\r
         \r
         mOkButton = findViewById(R.id.buttonOK);\r
 \r
@@ -265,21 +277,19 @@ SsoWebViewClientListener, OnSslUntrustedCertListener {
 \r
     private String chooseAuthTokenType(boolean oauth, boolean saml) {\r
         if (saml) {\r
-            return AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType());\r
+            return SAML_TOKEN_TYPE;\r
         } else if (oauth) {\r
-             return AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType());\r
+             return OAUTH_TOKEN_TYPE;\r
         } else {\r
-            return AccountTypeUtils.getAuthTokenTypePass(MainApp.getAccountType());\r
+            return BASIC_TOKEN_TYPE;\r
         }\r
     }\r
 \r
     \r
     /**\r
      * Configures elements in the user interface under direct control of the Activity.\r
-     * \r
-     * @param savedInstanceState        Saved activity state, as in {{@link #onCreate(Bundle)}\r
      */\r
-    private void initOverallUi(Bundle savedInstanceState) {\r
+    private void initOverallUi() {\r
         \r
         /// step 1 - load and process relevant inputs (resources, intent, savedInstanceState)\r
         boolean isWelcomeLinkVisible = getResources().getBoolean(R.bool.show_welcome_link);\r
@@ -415,9 +425,9 @@ SsoWebViewClientListener, OnSslUntrustedCertListener {
                     if (\r
                             AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(\r
                                     MainApp.getAccountType()\r
-                                    ).equals(mAuthTokenType) &&\r
-                            mHostUrlInput.hasFocus()\r
-                    ) {\r
+                            ).equals(mAuthTokenType) &&\r
+                                    mHostUrlInput.hasFocus()\r
+                            ) {\r
                         checkOcServer();\r
                     }\r
                 }\r
@@ -549,7 +559,7 @@ SsoWebViewClientListener, OnSslUntrustedCertListener {
      * intended to defer the processing of the redirection caught in \r
      * {@link #onNewIntent(Intent)} until {@link #onResume()} \r
      * \r
-     * See {@link #loadSavedInstanceState(Bundle)}\r
+     * See {@link #onSaveInstanceState(Bundle)}\r
      */\r
     @Override\r
     protected void onSaveInstanceState(Bundle outState) {\r
@@ -581,9 +591,42 @@ SsoWebViewClientListener, OnSslUntrustedCertListener {
         /// authentication\r
         outState.putBoolean(KEY_AUTH_IS_FIRST_ATTEMPT_TAG, mIsFirstAuthAttempt);\r
 \r
+        /// AsyncTask (User and password)\r
+        outState.putString(KEY_USERNAME, mUsernameInput.getText().toString());\r
+        outState.putString(KEY_PASSWORD, mPasswordInput.getText().toString());\r
+\r
+        if (mAsyncTask != null) {\r
+            mAsyncTask.cancel(true);\r
+            outState.putBoolean(KEY_ASYNC_TASK_IN_PROGRESS, true);\r
+        } else {\r
+            outState.putBoolean(KEY_ASYNC_TASK_IN_PROGRESS, false);\r
+        }\r
+        mAsyncTask = null;\r
+\r
         //Log_OC.wtf(TAG, "onSaveInstanceState end" );\r
     }\r
 \r
+    @Override\r
+    public void onRestoreInstanceState(Bundle savedInstanceState) {\r
+        super.onRestoreInstanceState(savedInstanceState);\r
+\r
+        // AsyncTask\r
+        boolean inProgress = savedInstanceState.getBoolean(KEY_ASYNC_TASK_IN_PROGRESS);\r
+        if (inProgress){\r
+            String username = savedInstanceState.getString(KEY_USERNAME);\r
+            String password = savedInstanceState.getString(KEY_PASSWORD);\r
+\r
+            OwnCloudCredentials credentials = null;\r
+            if (BASIC_TOKEN_TYPE.equals(mAuthTokenType)) {\r
+                credentials = OwnCloudCredentialsFactory.newBasicCredentials(username, password);\r
+\r
+            } else if (OAUTH_TOKEN_TYPE.equals(mAuthTokenType)) {\r
+                credentials = OwnCloudCredentialsFactory.newBearerCredentials(mAuthToken);\r
+\r
+            }\r
+            accessRootFolder(credentials);\r
+        }\r
+    }\r
 \r
     /**\r
      * The redirection triggered by the OAuth authentication server as response to the \r
@@ -608,7 +651,6 @@ SsoWebViewClientListener, OnSslUntrustedCertListener {
      */\r
     @Override\r
     protected void onResume() {\r
-        //Log_OC.wtf(TAG, "onResume init" );\r
         super.onResume();\r
         \r
         // bound here to avoid spurious changes triggered by Android on device rotations\r
@@ -623,15 +665,12 @@ SsoWebViewClientListener, OnSslUntrustedCertListener {
             doOnResumeAndBound();\r
         }\r
         \r
-        //Log_OC.wtf(TAG, "onResume end" );\r
     }\r
 \r
     \r
     @Override\r
     protected void onPause() {\r
-        //Log_OC.wtf(TAG, "onPause init" );\r
         if (mOperationsServiceBinder != null) {\r
-            //Log_OC.wtf(TAG, "unregistering to listen for operation callbacks" );\r
             mOperationsServiceBinder.removeOperationListener(this);\r
         }\r
         \r
@@ -639,7 +678,6 @@ SsoWebViewClientListener, OnSslUntrustedCertListener {
         mHostUrlInput.setOnFocusChangeListener(null);\r
         \r
         super.onPause();\r
-        //Log_OC.wtf(TAG, "onPause end" );\r
     }\r
     \r
     @Override\r
@@ -695,14 +733,14 @@ SsoWebViewClientListener, OnSslUntrustedCertListener {
     public void onFocusChange(View view, boolean hasFocus) {\r
         if (view.getId() == R.id.hostUrlInput) {   \r
             if (!hasFocus) {\r
-                onUrlInputFocusLost((TextView) view);\r
+                onUrlInputFocusLost();\r
             }\r
             else {\r
                 showRefreshButton(false);\r
             }\r
 \r
         } else if (view.getId() == R.id.account_password) {\r
-            onPasswordFocusChanged((TextView) view, hasFocus);\r
+            onPasswordFocusChanged(hasFocus);\r
         }\r
     }\r
 \r
@@ -715,10 +753,8 @@ SsoWebViewClientListener, OnSslUntrustedCertListener {
      * 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
      */\r
-    private void onUrlInputFocusLost(TextView hostInput) {\r
+    private void onUrlInputFocusLost() {\r
         if (!mServerInfo.mBaseUrl.equals(\r
                 normalizeUrl(mHostUrlInput.getText().toString(), mServerInfo.mIsSslConn))) {\r
             // check server again only if the user changed something in the field\r
@@ -772,10 +808,9 @@ SsoWebViewClientListener, OnSslUntrustedCertListener {
      * \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
+    private void onPasswordFocusChanged(boolean hasFocus) {\r
         if (hasFocus) {\r
             showViewPasswordButton();\r
         } else {\r
@@ -840,7 +875,6 @@ SsoWebViewClientListener, OnSslUntrustedCertListener {
             mServerStatusText = R.string.auth_wtf_reenter_URL;\r
             showServerStatus();\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
@@ -873,25 +907,17 @@ SsoWebViewClientListener, OnSslUntrustedCertListener {
         dialog.show(getSupportFragmentManager(), WAIT_DIALOG_TAG);\r
 \r
         /// validate credentials accessing the root folder\r
-        accessRootFolderRemoteOperation(username, password);\r
-        \r
+        OwnCloudCredentials credentials = OwnCloudCredentialsFactory.newBasicCredentials(username, password);\r
+        accessRootFolder(credentials);\r
     }\r
 \r
-    private void accessRootFolderRemoteOperation(String username, String password) {\r
-        Intent existenceCheckIntent = new Intent();\r
-        existenceCheckIntent.setAction(OperationsService.ACTION_EXISTENCE_CHECK);\r
-        existenceCheckIntent.putExtra(OperationsService.EXTRA_SERVER_URL, mServerInfo.mBaseUrl);\r
-        existenceCheckIntent.putExtra(OperationsService.EXTRA_REMOTE_PATH, "/");\r
-        existenceCheckIntent.putExtra(OperationsService.EXTRA_USERNAME, username);\r
-        existenceCheckIntent.putExtra(OperationsService.EXTRA_PASSWORD, password);\r
-        existenceCheckIntent.putExtra(OperationsService.EXTRA_AUTH_TOKEN, mAuthToken);\r
-        \r
-        if (mOperationsServiceBinder != null) {\r
-            //Log_OC.wtf(TAG, "starting existenceCheckRemoteOperation..." );\r
-            mWaitingForOpId = mOperationsServiceBinder.queueNewOperation(existenceCheckIntent);\r
-        }\r
+    private void accessRootFolder(OwnCloudCredentials credentials) {\r
+        mAsyncTask = new AuthenticatorAsyncTask(this);\r
+        Object[] params = { mServerInfo.mBaseUrl, credentials };\r
+        mAsyncTask.execute(params);\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
@@ -929,17 +955,16 @@ SsoWebViewClientListener, OnSslUntrustedCertListener {
      * in the server.\r
      */\r
     private void startSamlBasedFederatedSingleSignOnAuthorization() {\r
-        // be gentle with the user\r
+        /// be gentle with the user\r
         mAuthStatusIcon = R.drawable.progress_small;\r
         mAuthStatusText = R.string.auth_connecting_auth_server;\r
         showAuthStatus();\r
-        IndeterminateProgressDialog dialog = \r
-                IndeterminateProgressDialog.newInstance(R.string.auth_trying_to_login, true);\r
-        dialog.show(getSupportFragmentManager(), WAIT_DIALOG_TAG);\r
-\r
-        /// validate credentials accessing the root folder\r
-        accessRootFolderRemoteOperation("", "");\r
 \r
+        /// Show SAML-based SSO web dialog\r
+        String targetUrl = mServerInfo.mBaseUrl\r
+                + AccountUtils.getWebdavPath(mServerInfo.mVersion, mAuthTokenType);\r
+        SamlWebViewDialog dialog = SamlWebViewDialog.newInstance(targetUrl, targetUrl);\r
+        dialog.show(getSupportFragmentManager(), SAML_DIALOG_TAG);\r
     }\r
 \r
     /**\r
@@ -959,15 +984,6 @@ SsoWebViewClientListener, OnSslUntrustedCertListener {
         } else if (operation instanceof OAuth2GetAccessToken) {\r
             onGetOAuthAccessTokenFinish(result);\r
 \r
-        } else if (operation instanceof ExistenceCheckRemoteOperation)  {\r
-            //Log_OC.wtf(TAG, "received detection response through callback" );\r
-            if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()).\r
-                    equals(mAuthTokenType)) {\r
-                onSamlBasedFederatedSingleSignOnAuthorizationStart(result);\r
-\r
-            } else {\r
-                onAuthorizationCheckFinish(result);\r
-            }\r
         } else if (operation instanceof GetRemoteUserNameOperation) {\r
             onGetUserNameFinish(result);\r
         }\r
@@ -988,20 +1004,20 @@ SsoWebViewClientListener, OnSslUntrustedCertListener {
                 if (!mUsernameInput.getText().toString().equals(username)) {\r
                     // fail - not a new account, but an existing one; disallow\r
                     result = new RemoteOperationResult(ResultCode.ACCOUNT_NOT_THE_SAME);\r
-                    /*\r
-                    OwnCloudClientManagerFactory.getDefaultSingleton().removeClientFor(\r
-                            new OwnCloudAccount(\r
-                                    Uri.parse(mServerInfo.mBaseUrl),\r
-                                    OwnCloudCredentialsFactory.newSamlSsoCredentials(mAuthToken))\r
-                            );\r
-                            */\r
                     mAuthToken = "";\r
                     updateAuthStatusIconAndText(result);\r
                     showAuthStatus();\r
                     Log_OC.d(TAG, result.getLogMessage());\r
                 } else {\r
-                    updateToken();\r
-                    success = true;\r
+                    try {\r
+                        updateAccountAuthentication();\r
+                        success = true;\r
+\r
+                    } catch (AccountNotFoundException e) {\r
+                        Log_OC.e(TAG, "Account " + mAccount + " was removed!", e);\r
+                        Toast.makeText(this, R.string.auth_account_does_not_exist, Toast.LENGTH_SHORT).show();\r
+                        finish();\r
+                    }\r
                 }\r
             }\r
 \r
@@ -1015,36 +1031,10 @@ SsoWebViewClientListener, OnSslUntrustedCertListener {
 \r
     }\r
 \r
-    private void onSamlBasedFederatedSingleSignOnAuthorizationStart(RemoteOperationResult result) {\r
-        mWaitingForOpId = Long.MAX_VALUE;\r
-        dismissDialog(WAIT_DIALOG_TAG);\r
-
-        if (result.isIdPRedirection()) {
-            String url = result.getRedirectedLocation();\r
-            String targetUrl = mServerInfo.mBaseUrl \r
-                    + AccountUtils.getWebdavPath(mServerInfo.mVersion, mAuthTokenType);\r
-\r
-            // Show dialog\r
-            SamlWebViewDialog dialog = SamlWebViewDialog.newInstance(url, targetUrl);            \r
-            dialog.show(getSupportFragmentManager(), SAML_DIALOG_TAG);\r
-\r
-            mAuthStatusIcon = 0;\r
-            mAuthStatusText = 0;\r
-\r
-        } else {\r
-            mAuthStatusIcon = R.drawable.common_error;\r
-            mAuthStatusText = R.string.auth_unsupported_auth_method;\r
-\r
-        }\r
-        showAuthStatus();\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
+     *\r
      * @param result        Result of the check.\r
      */\r
     private void onGetServerInfoFinish(RemoteOperationResult result) {\r
@@ -1089,16 +1079,12 @@ SsoWebViewClientListener, OnSslUntrustedCertListener {
 \r
 \r
     private boolean authSupported(AuthenticationMethod authMethod) {\r
-        String basic = AccountTypeUtils.getAuthTokenTypePass(MainApp.getAccountType());\r
-        String oAuth = AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType());\r
-        String saml =  AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType());\r
-        \r
-        return (( mAuthTokenType.equals(basic) && \r
-                    authMethod.equals(AuthenticationMethod.BASIC_HTTP_AUTH) ) ||\r
-                ( mAuthTokenType.equals(oAuth) && \r
-                    authMethod.equals(AuthenticationMethod.BEARER_TOKEN)) ||\r
-                ( mAuthTokenType.equals(saml)  && \r
-                    authMethod.equals(AuthenticationMethod.SAML_WEB_SSO))\r
+        return (( BASIC_TOKEN_TYPE.equals(mAuthTokenType) &&\r
+                    AuthenticationMethod.BASIC_HTTP_AUTH.equals(authMethod) ) ||\r
+                ( OAUTH_TOKEN_TYPE.equals(mAuthTokenType) &&\r
+                    AuthenticationMethod.BEARER_TOKEN.equals(authMethod)) ||\r
+                ( SAML_TOKEN_TYPE.equals(mAuthTokenType)  &&\r
+                    AuthenticationMethod.SAML_WEB_SSO.equals(authMethod))\r
         );\r
     }\r
 \r
@@ -1339,8 +1325,10 @@ SsoWebViewClientListener, OnSslUntrustedCertListener {
             Map<String, String> tokens = (Map<String, String>)(result.getData().get(0));\r
             mAuthToken = tokens.get(OAuth2Constants.KEY_ACCESS_TOKEN);\r
             Log_OC.d(TAG, "Got ACCESS TOKEN: " + mAuthToken);\r
-            \r
-            accessRootFolderRemoteOperation("", "");\r
+\r
+            /// validate token accessing to root folder / getting session\r
+            OwnCloudCredentials credentials = OwnCloudCredentialsFactory.newBearerCredentials(mAuthToken);\r
+            accessRootFolder(credentials);\r
 \r
         } else {\r
             updateAuthStatusIconAndText(result);\r
@@ -1354,11 +1342,11 @@ SsoWebViewClientListener, OnSslUntrustedCertListener {
      * 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
+     *\r
      * @param result        Result of the operation.\r
      */\r
-    private void onAuthorizationCheckFinish(RemoteOperationResult result) {\r
+    @Override\r
+    public void onAuthenticatorTaskCallback(RemoteOperationResult result) {\r
         mWaitingForOpId = Long.MAX_VALUE;\r
         dismissDialog(WAIT_DIALOG_TAG);\r
 \r
@@ -1370,15 +1358,22 @@ SsoWebViewClientListener, OnSslUntrustedCertListener {
                 success = createAccount();\r
 \r
             } else {\r
-                updateToken();\r
-                success = true;\r
+                try {\r
+                    updateAccountAuthentication();\r
+                    success = true;\r
+\r
+                } catch (AccountNotFoundException e) {\r
+                    Log_OC.e(TAG, "Account " + mAccount + " was removed!", e);\r
+                    Toast.makeText(this, R.string.auth_account_does_not_exist, Toast.LENGTH_SHORT).show();\r
+                    finish();\r
+                }\r
             }\r
 \r
             if (success) {\r
                 finish();\r
             }\r
             \r
-        } else if (result.isServerFail() || result.isException()) {
+        } else if (result.isServerFail() || result.isException()) {\r
             /// server errors or exceptions in authorization take to requiring a new check of \r
             /// the server\r
             mServerIsChecked = true;\r
@@ -1412,10 +1407,16 @@ SsoWebViewClientListener, OnSslUntrustedCertListener {
 \r
 \r
     /**\r
-     * Sets the proper response to get that the Account Authenticator that started this activity \r
+     * Updates the authentication token.\r
+     *\r
+     * Sets the proper response so that the AccountAuthenticator that started this activity\r
      * saves a new authorization token for mAccount.\r
+     *\r
+     * Kills the session kept by OwnCloudClientManager so that a new one will created with\r
+     * the new credentials when needed.\r
      */\r
-    private void updateToken() {\r
+    private void updateAccountAuthentication() throws AccountNotFoundException {\r
+        \r
         Bundle response = new Bundle();\r
         response.putString(AccountManager.KEY_ACCOUNT_NAME, mAccount.name);\r
         response.putString(AccountManager.KEY_ACCOUNT_TYPE, mAccount.type);\r
@@ -1501,21 +1502,19 @@ SsoWebViewClientListener, OnSslUntrustedCertListener {
             final Intent intent = new Intent();       \r
             intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE,    MainApp.getAccountType());\r
             intent.putExtra(AccountManager.KEY_ACCOUNT_NAME,    mAccount.name);\r
-            /*if (!isOAuth)\r
-                intent.putExtra(AccountManager.KEY_AUTHTOKEN,   MainApp.getAccountType()); */\r
             intent.putExtra(AccountManager.KEY_USERDATA,        username);\r
             if (isOAuth || isSaml) {\r
                 mAccountMgr.setAuthToken(mAccount, mAuthTokenType, mAuthToken);\r
             }\r
             /// add user data to the new account; TODO probably can be done in the last parameter \r
-            //      addAccountExplicitly, or in KEY_USERDATA
+            //      addAccountExplicitly, or in KEY_USERDATA\r
             mAccountMgr.setUserData(\r
                     mAccount, Constants.KEY_OC_VERSION,    mServerInfo.mVersion.getVersion()\r
             );\r
             mAccountMgr.setUserData(\r
                     mAccount, Constants.KEY_OC_BASE_URL,   mServerInfo.mBaseUrl\r
             );\r
-
+\r
             if (isSaml) {\r
                 mAccountMgr.setUserData(mAccount, Constants.KEY_SUPPORTS_SAML_WEB_SSO, "TRUE"); \r
             } else if (isOAuth) {\r
@@ -1547,9 +1546,7 @@ SsoWebViewClientListener, OnSslUntrustedCertListener {
     /**\r
      * Updates the content and visibility state of the icon and text associated\r
      * to the last check on the ownCloud server.\r
-     * \r
-     * @param serverStatusText      Resource identifier of the text to show.\r
-     * @param serverStatusIcon      Resource identifier of the icon to show.\r
+     *\r
      */\r
     private void showServerStatus() {\r
         if (mServerStatusIcon == 0 && mServerStatusText == 0) {\r
@@ -1627,9 +1624,9 @@ SsoWebViewClientListener, OnSslUntrustedCertListener {
     public void onCheckClick(View view) {\r
         CheckBox oAuth2Check = (CheckBox)view;\r
         if (oAuth2Check.isChecked()) {\r
-            mAuthTokenType = AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType());\r
+            mAuthTokenType = OAUTH_TOKEN_TYPE;\r
         } else {\r
-            mAuthTokenType = AccountTypeUtils.getAuthTokenTypePass(MainApp.getAccountType());\r
+            mAuthTokenType = BASIC_TOKEN_TYPE;\r
         }\r
         updateAuthenticationPreFragmentVisibility();\r
     }\r
@@ -1703,7 +1700,6 @@ SsoWebViewClientListener, OnSslUntrustedCertListener {
         getUserNameIntent.putExtra(OperationsService.EXTRA_COOKIE, sessionCookie);\r
         \r
         if (mOperationsServiceBinder != null) {\r
-            //Log_OC.wtf(TAG, "starting getRemoteUserNameOperation..." );\r
             mWaitingForOpId = mOperationsServiceBinder.queueNewOperation(getUserNameIntent);\r
         }\r
     }\r
@@ -1836,7 +1832,6 @@ SsoWebViewClientListener, OnSslUntrustedCertListener {
             if (component.equals(\r
                     new ComponentName(AuthenticatorActivity.this, OperationsService.class)\r
                 )) {\r
-                //Log_OC.wtf(TAG, "Operations service connected");\r
                 mOperationsServiceBinder = (OperationsServiceBinder) service;\r
                 \r
                 doOnResumeAndBound();\r
@@ -1892,4 +1887,6 @@ SsoWebViewClientListener, OnSslUntrustedCertListener {
     public void doNegativeAuthenticatioDialogClick(){\r
         mIsFirstAuthAttempt = true;\r
     }\r
+\r
+\r
 }\r
diff --git a/src/com/owncloud/android/authentication/AuthenticatorAsyncTask.java b/src/com/owncloud/android/authentication/AuthenticatorAsyncTask.java
new file mode 100644 (file)
index 0000000..be15d1c
--- /dev/null
@@ -0,0 +1,101 @@
+/**
+ *   ownCloud Android client application
+ *
+ *   @author masensio on 09/02/2015.
+ *   Copyright (C) 2015 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.Activity;
+import android.content.Context;
+import android.net.Uri;
+import android.os.AsyncTask;
+
+import com.owncloud.android.lib.common.OwnCloudClient;
+import com.owncloud.android.lib.common.OwnCloudClientFactory;
+import com.owncloud.android.lib.common.OwnCloudCredentials;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult;
+import com.owncloud.android.lib.resources.files.ExistenceCheckRemoteOperation;
+
+import java.lang.ref.WeakReference;
+
+
+/**
+ * Async Task to verify the credentials of a user
+ */
+public class AuthenticatorAsyncTask  extends AsyncTask<Object, Void, RemoteOperationResult> {
+
+    private static String REMOTE_PATH = "/";
+    private static boolean SUCCESS_IF_ABSENT = false;
+
+    private Context mContext;
+    private final WeakReference<OnAuthenticatorTaskListener> mListener;
+    protected Activity mActivity;
+
+    public AuthenticatorAsyncTask(Activity activity) {
+        mContext = activity.getApplicationContext();
+        mListener = new WeakReference<OnAuthenticatorTaskListener>((OnAuthenticatorTaskListener)activity);
+    }
+
+    @Override
+    protected RemoteOperationResult doInBackground(Object... params) {
+
+        RemoteOperationResult result;
+        if (params!= null && params.length==2) {
+            String url = (String)params[0];
+            OwnCloudCredentials credentials = (OwnCloudCredentials)params[1];
+
+            // Client
+            Uri uri = Uri.parse(url);
+            OwnCloudClient client = OwnCloudClientFactory.createOwnCloudClient(uri, mContext, true);
+
+            client.setCredentials(credentials);
+
+            // Operation
+            ExistenceCheckRemoteOperation operation = new ExistenceCheckRemoteOperation(
+                    REMOTE_PATH,
+                    mContext,
+                    SUCCESS_IF_ABSENT
+            );
+            result = operation.execute(client);
+
+        } else {
+            result = new RemoteOperationResult(RemoteOperationResult.ResultCode.UNKNOWN_ERROR);
+        }
+
+        return result;
+    }
+
+    @Override
+    protected void onPostExecute(RemoteOperationResult result) {
+
+        if (result!= null)
+        {
+            OnAuthenticatorTaskListener listener = mListener.get();
+            if (listener!= null)
+            {
+                listener.onAuthenticatorTaskCallback(result);
+            }
+        }
+    }
+    /*
+     * Interface to retrieve data from recognition task
+     */
+    public interface OnAuthenticatorTaskListener{
+
+        void onAuthenticatorTaskCallback(RemoteOperationResult result);
+    }
+}
index f96b627..f6bd664 100644 (file)
@@ -1,5 +1,8 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2013 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
+ *   Copyright (C) 2015 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,
@@ -21,8 +24,6 @@ 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 {
index b90ab85..46a980b 100644 (file)
@@ -1,5 +1,8 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2013 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
+ *   Copyright (C) 2015 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,
@@ -50,8 +53,6 @@ import android.webkit.WebViewClient;
  * 
  * Assumes that the single-sign-on is kept thanks to a cookie set at the end of the
  * authentication process.
- *   
- * @author David A. Velasco
  */
 public class SsoWebViewClient extends WebViewClient {
         
@@ -124,7 +125,7 @@ public class SsoWebViewClient extends WebViewClient {
             view.setVisibility(View.GONE);
             CookieManager cookieManager = CookieManager.getInstance();
             final String cookies = cookieManager.getCookie(url);
-            Log_OC.d(TAG, "Cookies: " + cookies);
+            //Log_OC.d(TAG, "Cookies: " + cookies);
             if (mListenerHandler != null && mListenerRef != null) {
                 // this is good idea because onPageFinished is not running in the UI thread
                 mListenerHandler.post(new Runnable() {
@@ -141,22 +142,14 @@ public class SsoWebViewClient extends WebViewClient {
         } 
     }
     
-    
-    @Override
-    public void doUpdateVisitedHistory (WebView view, String url, boolean isReload) {
-        Log_OC.d(TAG, "doUpdateVisitedHistory : " + url);
-    }
-    
     @Override
     public void onReceivedSslError (final WebView view, final SslErrorHandler handler, SslError error) {
-        Log_OC.d(TAG, "onReceivedSslError : " + error);
+        Log_OC.e(TAG, "onReceivedSslError : " + error);
         // Test 1
         X509Certificate x509Certificate = getX509CertificateFromError(error);
         boolean isKnownServer = false;
         
         if (x509Certificate != null) {
-            Log_OC.d(TAG, "------>>>>> x509Certificate " + x509Certificate.toString());
-            
             try {
                 isKnownServer = NetworkUtils.isCertInKnownServersStore((Certificate) x509Certificate, mContext);
             } catch (Exception e) {
@@ -201,36 +194,4 @@ public class SsoWebViewClient extends WebViewClient {
         ((AuthenticatorActivity)mContext).createAuthenticationDialog(view, handler);
     }
 
-    @Override
-    public WebResourceResponse shouldInterceptRequest (WebView view, String url) {
-        Log_OC.d(TAG, "shouldInterceptRequest : " + url);
-        return null;
-    }
-    
-    @Override
-    public void onLoadResource (WebView view, String url) {
-        Log_OC.d(TAG, "onLoadResource : " + url);   
-    }
-    
-    @Override
-    public void onReceivedLoginRequest (WebView view, String realm, String account, String args) {
-        Log_OC.d(TAG, "onReceivedLoginRequest : " + realm + ", " + account + ", " + args);
-    }
-    
-    @Override
-    public void onScaleChanged (WebView view, float oldScale, float newScale) {
-        Log_OC.d(TAG, "onScaleChanged : " + oldScale + " -> " + newScale);
-        super.onScaleChanged(view, oldScale, newScale);
-    }
-
-    @Override
-    public void onUnhandledKeyEvent (WebView view, KeyEvent event) {
-        Log_OC.d(TAG, "onUnhandledKeyEvent : " + event);
-    }
-    
-    @Override
-    public boolean shouldOverrideKeyEvent (WebView view, KeyEvent event) {
-        Log_OC.d(TAG, "shouldOverrideKeyEvent : " + event);
-        return false;
-    }
 }
index 1f626d3..a197e08 100644 (file)
@@ -1,6 +1,8 @@
-/* ownCloud Android client application
+/**
+ *   ownCloud Android client application
+ *
  *   Copyright (C) 2012  Bartek Przybylski
- *   Copyright (C) 2012-2014 ownCloud Inc.
+ *   Copyright (C) 2015 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,
@@ -46,6 +48,7 @@ import android.content.OperationApplicationException;
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.RemoteException;
+import android.provider.MediaStore;
 
 public class FileDataStorageManager {
 
@@ -262,8 +265,8 @@ public class FileDataStorageManager {
      * HERE ONLY DATA CONSISTENCY SHOULD BE GRANTED
      *  
      * @param folder
-     * @param files
-     * @param removeNotUpdated
+     * @param updatedFiles
+     * @param filesToRemove
      */
     public void saveFolder(
             OCFile folder, Collection<OCFile> updatedFiles, Collection<OCFile> filesToRemove
@@ -493,7 +496,7 @@ public class FileDataStorageManager {
                 if (removeLocalCopy && file.isDown() && localPath != null && success) {
                     success = new File(localPath).delete();
                     if (success) {
-                        triggerMediaScan(localPath);
+                        deleteFileInMediaScan(localPath);
                     }
                     if (!removeDBData && success) {
                         // maybe unnecessary, but should be checked TODO remove if unnecessary
@@ -541,7 +544,8 @@ public class FileDataStorageManager {
 
     private boolean removeLocalFolder(OCFile folder) {
         boolean success = true;
-        File localFolder = new File(FileStorageUtils.getDefaultSavePathFor(mAccount.name, folder));
+        String localFolderPath = FileStorageUtils.getDefaultSavePathFor(mAccount.name, folder);
+        File localFolder = new File(localFolderPath);
         if (localFolder.exists()) {
             // stage 1: remove the local files already registered in the files database
             Vector<OCFile> files = getFolderContent(folder.getFileId());
@@ -551,13 +555,13 @@ public class FileDataStorageManager {
                         success &= removeLocalFolder(file);
                     } else {
                         if (file.isDown()) {
-                            String path = file.getStoragePath();
                             File localFile = new File(file.getStoragePath());
                             success &= localFile.delete();
                             if (success) {
+                                // notify MediaScanner about removed file
+                                deleteFileInMediaScan(file.getStoragePath());
                                 file.setStoragePath(null);
                                 saveFile(file);
-                                triggerMediaScan(path); // notify MediaScanner about removed file
                             }
                         }
                     }
@@ -581,7 +585,6 @@ public class FileDataStorageManager {
                 } else {
                     String path = localFile.getAbsolutePath();
                     success &= localFile.delete();
-                    triggerMediaScan(path); // notify MediaScanner about removed file
                 }
             }
         }
@@ -716,7 +719,7 @@ public class FileDataStorageManager {
                 Iterator<String> it = originalPathsToTriggerMediaScan.iterator();
                 while (it.hasNext()) {
                     // Notify MediaScanner about removed file
-                    triggerMediaScan(it.next());
+                    deleteFileInMediaScan(it.next());
                 }
                 it = newPathsToTriggerMediaScan.iterator();
                 while (it.hasNext()) {
@@ -1498,4 +1501,46 @@ public class FileDataStorageManager {
         MainApp.getAppContext().sendBroadcast(intent);
     }
 
+    public void deleteFileInMediaScan(String path) {
+
+        String mimetypeString = FileStorageUtils.getMimeTypeFromName(path);
+        ContentResolver contentResolver = getContentResolver();
+
+        if (contentResolver != null) {
+            if (mimetypeString.startsWith("image/")) {
+                // Images
+                contentResolver.delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
+                        MediaStore.Images.Media.DATA + "=?", new String[]{path});
+            } else if (mimetypeString.startsWith("audio/")) {
+                // Audio
+                contentResolver.delete(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
+                        MediaStore.Audio.Media.DATA + "=?", new String[]{path});
+            } else if (mimetypeString.startsWith("video/")) {
+                // Video
+                contentResolver.delete(MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
+                        MediaStore.Video.Media.DATA + "=?", new String[]{path});
+            }
+        } else {
+            ContentProviderClient contentProviderClient = getContentProviderClient();
+            try {
+                if (mimetypeString.startsWith("image/")) {
+                    // Images
+                    contentProviderClient.delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
+                            MediaStore.Images.Media.DATA + "=?", new String[]{path});
+                } else if (mimetypeString.startsWith("audio/")) {
+                    // Audio
+                    contentProviderClient.delete(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
+                            MediaStore.Audio.Media.DATA + "=?", new String[]{path});
+                } else if (mimetypeString.startsWith("video/")) {
+                    // Video
+                    contentProviderClient.delete(MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
+                            MediaStore.Video.Media.DATA + "=?", new String[]{path});
+                }
+            } catch (RemoteException e) {
+                Log_OC.e(TAG, "Exception deleting media file in MediaStore " + e.getMessage());
+            }
+        }
+
+    }
+
 }
index e6fd414..2c9c53b 100644 (file)
@@ -1,6 +1,8 @@
-/* ownCloud Android client application
+/**
+ *   ownCloud Android client application
+ *
  *   Copyright (C) 2012  Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
+ *   Copyright (C) 2015 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,
@@ -20,9 +22,9 @@ package com.owncloud.android.datamodel;
 
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.webkit.MimeTypeMap;
 
 import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.utils.FileStorageUtils;
 
 import java.io.File;
 
@@ -538,17 +540,7 @@ public class OCFile implements Parcelable, Comparable<OCFile> {
      */
     public boolean isImage() {
         return ((mMimeType != null && mMimeType.startsWith("image/")) ||
-                getMimeTypeFromName().startsWith("image/"));
-    }
-
-    public String getMimeTypeFromName() {
-        String extension = "";
-        int pos = mRemotePath.lastIndexOf('.');
-        if (pos >= 0) {
-            extension = mRemotePath.substring(pos + 1);
-        }
-        String result = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension.toLowerCase());
-        return (result != null) ? result : "";
+                FileStorageUtils.getMimeTypeFromName(mRemotePath).startsWith("image/"));
     }
 
     public String getPermissions() {
index edab29d..87fa43f 100644 (file)
@@ -1,5 +1,9 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2014 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   @author Tobias Kaminsky
+ *   @author David A. Velasco
+ *   Copyright (C) 2015 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,
@@ -49,10 +53,7 @@ import com.owncloud.android.utils.BitmapUtils;
 import com.owncloud.android.utils.DisplayUtils;
 
 /**
- * Manager for concurrent access to thumbnails cache. 
- *  
- * @author Tobias Kaminsky
- * @author David A. Velasco
+ * Manager for concurrent access to thumbnails cache.
  */
 public class ThumbnailsCacheManager {
     
@@ -173,7 +174,7 @@ public class ThumbnailsCacheManager {
                 }
 
                 mFile = params[0];
-
+                
                 if (mFile instanceof OCFile) {
                     thumbnail = doOCFileInBackground();
                 }  else if (mFile instanceof File) {
@@ -243,7 +244,7 @@ public class ThumbnailsCacheManager {
         private int getThumbnailDimension(){
             // Converts dp to pixel
             Resources r = MainApp.getAppContext().getResources();
-            return (int) Math.round(r.getDimension(R.dimen.file_icon_size));
+            return (int) Math.round(r.getDimension(R.dimen.file_icon_size_grid));
         }
 
         private Bitmap doOCFileInBackground() {
index 3682a7b..6611306 100644 (file)
@@ -1,6 +1,9 @@
-/* ownCloud Android client application
+/**
+ *   ownCloud Android client application
+ *
+ *   @author Bartek Przybylski
  *   Copyright (C) 2011-2012  Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
+ *   Copyright (C) 2015 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,
@@ -28,9 +31,6 @@ import android.database.sqlite.SQLiteOpenHelper;
 
 /**
  * Custom database helper for ownCloud
- * 
- * @author Bartek Przybylski
- * 
  */
 public class DbHandler {
     private SQLiteDatabase mDB;
index b6bfe4a..1f789d1 100644 (file)
@@ -1,6 +1,9 @@
-/* ownCloud Android client application\r
+/**\r
+ *   ownCloud Android client application\r
+ *\r
+ *   @author Bartek Przybylski\r
  *   Copyright (C) 2011  Bartek Przybylski\r
- *   Copyright (C) 2012-2013 ownCloud Inc.\r
+ *   Copyright (C) 2015 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
@@ -24,9 +27,6 @@ import com.owncloud.android.MainApp;
 \r
 /**\r
  * Meta-Class that holds various static field information\r
- * \r
- * @author Bartek Przybylski\r
- * \r
  */\r
 public class ProviderMeta {\r
 \r
index 4e139ae..2cf4358 100644 (file)
@@ -1,6 +1,9 @@
-/* ownCloud Android client application
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
  *   Copyright (C) 2012 Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
+ *   Copyright (C) 2015 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,
@@ -29,8 +32,6 @@ import android.content.Intent;
 /**
  * App-registered receiver catching the broadcast intent reporting that the system was 
  * just boot up.
- * 
- * @author David A. Velasco
  */
 public class BootupBroadcastReceiver extends BroadcastReceiver {
 
index 89b00dc..04e9fbc 100644 (file)
@@ -1,5 +1,8 @@
-/* ownCloud Android client application
- *   Copyright (C) 2014 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
+ *   Copyright (C) 2015 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,
@@ -38,8 +41,6 @@ import com.owncloud.android.ui.activity.ComponentsGetter;
 /**
  * Filters out the file actions available in a given {@link Menu} for a given {@link OCFile} 
  * according to the current state of the latest. 
- * 
- * @author David A. Velasco
  */
 public class FileMenuFilter {
 
index cf9f474..b2f74f2 100644 (file)
@@ -1,5 +1,9 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2015 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   @author masensio
+ *   @author David A. Velasco
+ *   Copyright (C) 2015 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,
@@ -41,9 +45,7 @@ import com.owncloud.android.ui.activity.FileActivity;
 import com.owncloud.android.ui.dialog.ShareLinkToDialog;
 
 /**
- * 
- * @author masensio
- * @author David A. Velasco
+ *
  */
 public class FileOperationsHelper {
 
@@ -117,7 +119,7 @@ public class FileOperationsHelper {
     }
     
     
-    public void shareFileWithLinkToApp(OCFile file, Intent sendIntent) {
+    public void shareFileWithLinkToApp(OCFile file, String password, Intent sendIntent) {
         
         if (file != null) {
             mFileActivity.showLoadingDialog();
@@ -126,6 +128,7 @@ public class FileOperationsHelper {
             service.setAction(OperationsService.ACTION_CREATE_SHARE);
             service.putExtra(OperationsService.EXTRA_ACCOUNT, mFileActivity.getAccount());
             service.putExtra(OperationsService.EXTRA_REMOTE_PATH, file.getRemotePath());
+            service.putExtra(OperationsService.EXTRA_PASSWORD_SHARE, password);
             service.putExtra(OperationsService.EXTRA_SEND_INTENT, sendIntent);
             mWaitingForOpId = mFileActivity.getOperationsServiceBinder().queueNewOperation(service);
             
index c1c3e9c..b52c36d 100644 (file)
@@ -1,6 +1,8 @@
-/* ownCloud Android client application
+/**
+ *   ownCloud Android client application
+ *
  *   Copyright (C) 2012  Bartek Przybylski
- *   Copyright (C) 2012-2014 ownCloud Inc.
+ *   Copyright (C) 2015 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,
index feedc11..f5be6a7 100644 (file)
@@ -1,4 +1,6 @@
-/* ownCloud Android client application
+/**
+ *   ownCloud Android client application
+ *
  *   Copyright (C) 2012 Bartek Przybylski
  *   Copyright (C) 2012-2015 ownCloud Inc.
  *
@@ -27,6 +29,7 @@ import java.util.Map;
 import java.util.Vector;
 
 import com.owncloud.android.R;
+import com.owncloud.android.authentication.AccountUtils;
 import com.owncloud.android.authentication.AuthenticatorActivity;
 import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
@@ -49,7 +52,9 @@ import com.owncloud.android.ui.preview.PreviewImageFragment;
 import com.owncloud.android.utils.ErrorMessageAdapter;
 
 import android.accounts.Account;
+import android.accounts.AccountManager;
 import android.accounts.AccountsException;
+import android.accounts.OnAccountsUpdateListener;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.app.Service;
@@ -64,19 +69,20 @@ import android.os.Process;
 import android.support.v4.app.NotificationCompat;
 import android.util.Pair;
 
-public class FileDownloader extends Service implements OnDatatransferProgressListener {
-    
+public class FileDownloader extends Service
+        implements OnDatatransferProgressListener, OnAccountsUpdateListener {
+
     public static final String EXTRA_ACCOUNT = "ACCOUNT";
     public static final String EXTRA_FILE = "FILE";
 
     private static final String DOWNLOAD_ADDED_MESSAGE = "DOWNLOAD_ADDED";
     private static final String DOWNLOAD_FINISH_MESSAGE = "DOWNLOAD_FINISH";
-    public static final String EXTRA_DOWNLOAD_RESULT = "RESULT";    
+    public static final String EXTRA_DOWNLOAD_RESULT = "RESULT";
     public static final String EXTRA_FILE_PATH = "FILE_PATH";
     public static final String EXTRA_REMOTE_PATH = "REMOTE_PATH";
     public static final String EXTRA_LINKED_TO_PATH = "LINKED_TO";
     public static final String ACCOUNT_NAME = "ACCOUNT_NAME";
-    
+
     private static final String TAG = "FileDownloader";
 
     private Looper mServiceLooper;
@@ -85,50 +91,77 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis
     private OwnCloudClient mDownloadClient = null;
     private Account mCurrentAccount = null;
     private FileDataStorageManager mStorageManager;
-    
+
     private IndexedForest<DownloadFileOperation> mPendingDownloads = new IndexedForest<DownloadFileOperation>();
 
     private DownloadFileOperation mCurrentDownload = null;
-    
+
     private NotificationManager mNotificationManager;
     private NotificationCompat.Builder mNotificationBuilder;
     private int mLastPercent;
 
-    
+
     public static String getDownloadAddedMessage() {
         return FileDownloader.class.getName() + DOWNLOAD_ADDED_MESSAGE;
     }
-    
+
     public static String getDownloadFinishMessage() {
         return FileDownloader.class.getName() + DOWNLOAD_FINISH_MESSAGE;
     }
-    
+
     /**
      * Service initialization
      */
     @Override
     public void onCreate() {
         super.onCreate();
+        Log_OC.d(TAG, "Creating service");
         mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
-        HandlerThread thread = new HandlerThread("FileDownloaderThread",
-                Process.THREAD_PRIORITY_BACKGROUND);
+        HandlerThread thread = new HandlerThread("FileDownloaderThread", Process.THREAD_PRIORITY_BACKGROUND);
         thread.start();
         mServiceLooper = thread.getLooper();
         mServiceHandler = new ServiceHandler(mServiceLooper, this);
         mBinder = new FileDownloaderBinder();
+
+        // add AccountsUpdatedListener
+        AccountManager am = AccountManager.get(getApplicationContext());
+        am.addOnAccountsUpdatedListener(this, null, false);
+    }
+
+
+    /**
+     * Service clean up
+     */
+    @Override
+    public void onDestroy() {
+        Log_OC.v(TAG, "Destroying service");
+        mBinder = null;
+        mServiceHandler = null;
+        mServiceLooper.quit();
+        mServiceLooper = null;
+        mNotificationManager = null;
+
+        // remove AccountsUpdatedListener
+        AccountManager am = AccountManager.get(getApplicationContext());
+        am.removeOnAccountsUpdatedListener(this);
+
+        super.onDestroy();
     }
 
+
     /**
      * Entry point to add one or several files to the queue of downloads.
-     *
+     * <p/>
      * New downloads are added calling to startService(), resulting in a call to this method.
      * This ensures the service will keep on working although the caller activity goes away.
      */
     @Override
     public int onStartCommand(Intent intent, int flags, int startId) {
-        if (    !intent.hasExtra(EXTRA_ACCOUNT) ||
+        Log_OC.d(TAG, "Starting command with id " + startId);
+
+        if (!intent.hasExtra(EXTRA_ACCOUNT) ||
                 !intent.hasExtra(EXTRA_FILE)
-           ) {
+                ) {
             Log_OC.e(TAG, "Not enough information provided in intent");
             return START_NOT_STICKY;
         } else {
@@ -140,22 +173,22 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis
                     "Received request to download file"
             );*/
 
-                AbstractList<String> requestedDownloads = new Vector<String>();
-                try {
-                    DownloadFileOperation newDownload = new DownloadFileOperation(account, file);
-                    newDownload.addDatatransferProgressListener(this);
-                    newDownload.addDatatransferProgressListener((FileDownloaderBinder) mBinder);
-                    Pair<String, String> putResult = mPendingDownloads.putIfAbsent(
+            AbstractList<String> requestedDownloads = new Vector<String>();
+            try {
+                DownloadFileOperation newDownload = new DownloadFileOperation(account, file);
+                newDownload.addDatatransferProgressListener(this);
+                newDownload.addDatatransferProgressListener((FileDownloaderBinder) mBinder);
+                Pair<String, String> putResult = mPendingDownloads.putIfAbsent(
                         account, file.getRemotePath(), newDownload
-                    );
-                    String downloadKey = putResult.first;
-                    requestedDownloads.add(downloadKey);
+                );
+                String downloadKey = putResult.first;
+                requestedDownloads.add(downloadKey);
                     /*Log_OC.v(
                         "NOW " + TAG + ", thread " + Thread.currentThread().getName(),
                         "Download on " + file.getRemotePath() + " added to queue"
                     );*/
 
-                    // Store file on db with state 'downloading'
+                // Store file on db with state 'downloading'
                     /*
                     TODO - check if helps with UI responsiveness, letting only folders use FileDownloaderBinder to check
                     FileDataStorageManager storageManager = new FileDataStorageManager(account, getContentResolver());
@@ -163,19 +196,19 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis
                     storageManager.saveFile(file);
                     */
 
-                    sendBroadcastNewDownload(newDownload, putResult.second);
+                sendBroadcastNewDownload(newDownload, putResult.second);
 
-                } catch (IllegalArgumentException e) {
-                    Log_OC.e(TAG, "Not enough information provided in intent: " + e.getMessage());
-                    return START_NOT_STICKY;
-                }
+            } catch (IllegalArgumentException e) {
+                Log_OC.e(TAG, "Not enough information provided in intent: " + e.getMessage());
+                return START_NOT_STICKY;
+            }
 
-                if (requestedDownloads.size() > 0) {
-                    Message msg = mServiceHandler.obtainMessage();
-                    msg.arg1 = startId;
-                    msg.obj = requestedDownloads;
-                    mServiceHandler.sendMessage(msg);
-                }
+            if (requestedDownloads.size() > 0) {
+                Message msg = mServiceHandler.obtainMessage();
+                msg.arg1 = startId;
+                msg.obj = requestedDownloads;
+                mServiceHandler.sendMessage(msg);
+            }
             //}
         }
 
@@ -186,7 +219,7 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis
     /**
      * Provides a binder object that clients can use to perform operations on the queue of downloads,
      * excepting the addition of new files.
-     *
+     * <p/>
      * Implemented to perform cancellation, pause and resume of existing downloads.
      */
     @Override
@@ -200,19 +233,29 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis
      */
     @Override
     public boolean onUnbind(Intent intent) {
-        ((FileDownloaderBinder)mBinder).clearListeners();
+        ((FileDownloaderBinder) mBinder).clearListeners();
         return false;   // not accepting rebinding (default behaviour)
     }
 
+    @Override
+    public void onAccountsUpdated(Account[] accounts) {
+         //review the current download and cancel it if its account doesn't exist
+        if (mCurrentDownload != null &&
+                !AccountUtils.exists(mCurrentDownload.getAccount(), getApplicationContext())) {
+            mCurrentDownload.cancel();
+        }
+        // The rest of downloads are cancelled when they try to start
+    }
+
 
     /**
-     *  Binder to let client components to perform operations on the queue of downloads.
-     *
-     *  It provides by itself the available operations.
+     * Binder to let client components to perform operations on the queue of downloads.
+     * <p/>
+     * It provides by itself the available operations.
      */
     public class FileDownloaderBinder extends Binder implements OnDatatransferProgressListener {
-        
-        /** 
+
+        /**
          * Map of listeners that will be reported about progress of downloads from a {@link FileDownloaderBinder}
          * instance.
          */
@@ -223,8 +266,8 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis
         /**
          * Cancels a pending or current download of a remote file.
          *
-         * @param account       ownCloud account where the remote file is stored.
-         * @param file          A file in the queue of pending downloads
+         * @param account ownCloud account where the remote file is stored.
+         * @param file    A file in the queue of pending downloads
          */
         public void cancel(Account account, OCFile file) {
             /*Log_OC.v(
@@ -233,7 +276,8 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis
             );
             Log_OC.v(   "NOW " + TAG + ", thread " + Thread.currentThread().getName(),
                     "Removing download of " + file.getRemotePath());*/
-            Pair<DownloadFileOperation, String> removeResult = mPendingDownloads.remove(account, file.getRemotePath());
+            Pair<DownloadFileOperation, String> removeResult =
+                    mPendingDownloads.remove(account, file.getRemotePath());
             DownloadFileOperation download = removeResult.first;
             if (download != null) {
                 /*Log_OC.v(   "NOW " + TAG + ", thread " + Thread.currentThread().getName(),
@@ -249,8 +293,25 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis
                 }
             }
         }
-        
-        
+
+        /**
+         * Cancels a pending or current upload for an account
+         *
+         * @param account Owncloud accountName where the remote file will be stored.
+         */
+        public void cancel(Account account) {
+            Log_OC.d(TAG, "Account= " + account.name);
+
+            if (mCurrentDownload != null) {
+                Log_OC.d(TAG, "Current Download Account= " + mCurrentDownload.getAccount().name);
+                if (mCurrentDownload.getAccount().name.equals(account.name)) {
+                    mCurrentDownload.cancel();
+                }
+            }
+            // Cancel pending downloads
+            cancelDownloadsForAccount(account);
+        }
+
         public void clearListeners() {
             mBoundListeners.clear();
         }
@@ -259,43 +320,43 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis
         /**
          * Returns True when the file described by 'file' in the ownCloud account 'account' is downloading or
          * waiting to download.
-         * 
+         * <p/>
          * If 'file' is a directory, returns 'true' if any of its descendant files is downloading or
          * waiting to download.
-         * 
-         * @param account       ownCloud account where the remote file is stored.
-         * @param file          A file that could be in the queue of downloads.
+         *
+         * @param account ownCloud account where the remote file is stored.
+         * @param file    A file that could be in the queue of downloads.
          */
         public boolean isDownloading(Account account, OCFile file) {
             if (account == null || file == null) return false;
             return (mPendingDownloads.contains(account, file.getRemotePath()));
         }
 
-        
+
         /**
          * Adds a listener interested in the progress of the download for a concrete file.
-         * 
-         * @param listener      Object to notify about progress of transfer.    
-         * @param account       ownCloud account holding the file of interest.
-         * @param file          {@link OCFile} of interest for listener.
+         *
+         * @param listener Object to notify about progress of transfer.
+         * @param account  ownCloud account holding the file of interest.
+         * @param file     {@link OCFile} of interest for listener.
          */
-        public void addDatatransferProgressListener (
+        public void addDatatransferProgressListener(
                 OnDatatransferProgressListener listener, Account account, OCFile file
         ) {
             if (account == null || file == null || listener == null) return;
             //String targetKey = buildKey(account, file.getRemotePath());
             mBoundListeners.put(file.getFileId(), listener);
         }
-        
-        
+
+
         /**
          * Removes a listener interested in the progress of the download for a concrete file.
-         * 
-         * @param listener      Object to notify about progress of transfer.    
-         * @param account       ownCloud account holding the file of interest.
-         * @param file          {@link OCFile} of interest for listener.
+         *
+         * @param listener Object to notify about progress of transfer.
+         * @param account  ownCloud account holding the file of interest.
+         * @param file     {@link OCFile} of interest for listener.
          */
-        public void removeDatatransferProgressListener (
+        public void removeDatatransferProgressListener(
                 OnDatatransferProgressListener listener, Account account, OCFile file
         ) {
             if (account == null || file == null || listener == null) return;
@@ -308,25 +369,37 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis
 
         @Override
         public void onTransferProgress(long progressRate, long totalTransferredSoFar, long totalToTransfer,
-                String fileName) {
+                                       String fileName) {
             //String key = buildKey(mCurrentDownload.getAccount(), mCurrentDownload.getFile().getRemotePath());
             OnDatatransferProgressListener boundListener = mBoundListeners.get(mCurrentDownload.getFile().getFileId());
             if (boundListener != null) {
                 boundListener.onTransferProgress(progressRate, totalTransferredSoFar, totalToTransfer, fileName);
             }
         }
-        
+
+        /**
+         * Review downloads and cancel it if its account doesn't exist
+         */
+        public void checkAccountOfCurrentDownload() {
+            if (mCurrentDownload != null &&
+                    !AccountUtils.exists(mCurrentDownload.getAccount(), getApplicationContext())) {
+                mCurrentDownload.cancel();
+            }
+            // The rest of downloads are cancelled when they try to start
+        }
+
     }
-    
-    
-    /** 
-     * Download worker. Performs the pending downloads in the order they were requested. 
-     * 
-     * Created with the Looper of a new thread, started in {@link FileUploader#onCreate()}. 
+
+
+    /**
+     * Download worker. Performs the pending downloads in the order they were requested.
+     * <p/>
+     * Created with the Looper of a new thread, started in {@link FileUploader#onCreate()}.
      */
     private static class ServiceHandler extends Handler {
         // don't make it a final class, and don't remove the static ; lint will warn about a possible memory leak
         FileDownloader mService;
+
         public ServiceHandler(Looper looper, FileDownloader service) {
             super(looper);
             if (service == null)
@@ -342,20 +415,19 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis
                 Iterator<String> it = requestedDownloads.iterator();
                 while (it.hasNext()) {
                     String next = it.next();
-                    /*Log_OC.v(   "NOW " + TAG + ", thread " + Thread.currentThread().getName(),
-                            "Handling download file " + next);*/
                     mService.downloadFile(next);
                 }
             }
+            Log_OC.d(TAG, "Stopping after command with id " + msg.arg1);
             mService.stopSelf(msg.arg1);
         }
     }
-    
+
 
     /**
      * Core download method: requests a file to download and stores it.
-     * 
-     * @param downloadKey   Key to access the download to perform, contained in mPendingDownloads 
+     *
+     * @param downloadKey Key to access the download to perform, contained in mPendingDownloads
      */
     private void downloadFile(String downloadKey) {
 
@@ -364,54 +436,61 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis
         mCurrentDownload = mPendingDownloads.get(downloadKey);
 
         if (mCurrentDownload != null) {
-            
-            notifyDownloadStart(mCurrentDownload);
+            // Detect if the account exists
+            if (AccountUtils.exists(mCurrentDownload.getAccount(), getApplicationContext())) {
+                Log_OC.d(TAG, "Account " + mCurrentDownload.getAccount().name + " exists");
+                notifyDownloadStart(mCurrentDownload);
 
-            RemoteOperationResult downloadResult = null;
-            try {
-                /// prepare client object to send the request to the ownCloud server
-                if (mCurrentAccount == null || !mCurrentAccount.equals(mCurrentDownload.getAccount())) {
-                    mCurrentAccount = mCurrentDownload.getAccount();
-                    mStorageManager = new FileDataStorageManager(
-                            mCurrentAccount,
-                            getContentResolver()
-                    );
-                }   // else, reuse storage manager from previous operation
-
-                // always get client from client manager, to get fresh credentials in case of update
-                OwnCloudAccount ocAccount = new OwnCloudAccount(mCurrentAccount, this);
-                mDownloadClient = OwnCloudClientManagerFactory.getDefaultSingleton().
-                        getClientFor(ocAccount, this);
-
-
-                /// perform the download
-                /*Log_OC.v(   "NOW " + TAG + ", thread " + Thread.currentThread().getName(),
+                RemoteOperationResult downloadResult = null;
+                try {
+                    /// prepare client object to send the request to the ownCloud server
+                    if (mCurrentAccount == null || !mCurrentAccount.equals(mCurrentDownload.getAccount())) {
+                        mCurrentAccount = mCurrentDownload.getAccount();
+                        mStorageManager = new FileDataStorageManager(
+                                mCurrentAccount,
+                                getContentResolver()
+                        );
+                    }   // else, reuse storage manager from previous operation
+
+                    // always get client from client manager, to get fresh credentials in case of update
+                    OwnCloudAccount ocAccount = new OwnCloudAccount(mCurrentAccount, this);
+                    mDownloadClient = OwnCloudClientManagerFactory.getDefaultSingleton().
+                            getClientFor(ocAccount, this);
+
+
+                    /// perform the download
+                    /*Log_OC.v(   "NOW " + TAG + ", thread " + Thread.currentThread().getName(),
                         "Executing download of " + mCurrentDownload.getRemotePath());*/
-                downloadResult = mCurrentDownload.execute(mDownloadClient);
-                if (downloadResult.isSuccess()) {
-                    saveDownloadedFile();
-                }
-            
-            } catch (AccountsException e) {
-                Log_OC.e(TAG, "Error while trying to get authorization for " + mCurrentAccount.name, e);
-                downloadResult = new RemoteOperationResult(e);
-            } catch (IOException e) {
-                Log_OC.e(TAG, "Error while trying to get authorization for " + mCurrentAccount.name, e);
-                downloadResult = new RemoteOperationResult(e);
-                
-            } finally {
+                    downloadResult = mCurrentDownload.execute(mDownloadClient);
+                    if (downloadResult.isSuccess()) {
+                        saveDownloadedFile();
+                    }
+
+                } catch (AccountsException e) {
+                    Log_OC.e(TAG, "Error while trying to get authorization for " + mCurrentAccount.name, e);
+                    downloadResult = new RemoteOperationResult(e);
+                } catch (IOException e) {
+                    Log_OC.e(TAG, "Error while trying to get authorization for " + mCurrentAccount.name, e);
+                    downloadResult = new RemoteOperationResult(e);
+
+                } finally {
                 /*Log_OC.v(   "NOW " + TAG + ", thread " + Thread.currentThread().getName(),
                         "Removing payload " + mCurrentDownload.getRemotePath());*/
 
-                Pair<DownloadFileOperation, String> removeResult =
-                        mPendingDownloads.removePayload(mCurrentAccount, mCurrentDownload.getRemotePath());
+                    Pair<DownloadFileOperation, String> removeResult =
+                            mPendingDownloads.removePayload(mCurrentAccount, mCurrentDownload.getRemotePath());
 
-                /// notify result
-                notifyDownloadResult(mCurrentDownload, downloadResult);
+                    /// notify result
+                    notifyDownloadResult(mCurrentDownload, downloadResult);
 
-                sendBroadcastDownloadFinished(mCurrentDownload, downloadResult, removeResult.second);
-            }
+                    sendBroadcastDownloadFinished(mCurrentDownload, downloadResult, removeResult.second);
+                }
+            } else {
+                // Cancel the transfer
+                Log_OC.d(TAG, "Account " + mCurrentDownload.getAccount().toString() + " doesn't exist");
+                cancelDownloadsForAccount(mCurrentDownload.getAccount());
 
+            }
         }
     }
 
@@ -448,13 +527,13 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis
 
     /**
      * Creates a status notification to show the download progress
-     * 
-     * @param download  Download operation starting.
+     *
+     * @param download Download operation starting.
      */
     private void notifyDownloadStart(DownloadFileOperation download) {
         /// create status notification with a progress bar
         mLastPercent = 0;
-        mNotificationBuilder = 
+        mNotificationBuilder =
                 NotificationBuilderWithProgressBar.newNotificationBuilderWithProgressBar(this);
         mNotificationBuilder
                 .setSmallIcon(R.drawable.notification_icon)
@@ -466,7 +545,7 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis
                         String.format(getString(R.string.downloader_download_in_progress_content), 0,
                                 new File(download.getSavePath()).getName())
                 );
-                
+
         /// includes a pending intent in the notification showing the details view of the file
         Intent showDetailsIntent = null;
         if (PreviewImageFragment.canBePreviewed(download.getFile())) {
@@ -477,22 +556,21 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis
         showDetailsIntent.putExtra(FileActivity.EXTRA_FILE, download.getFile());
         showDetailsIntent.putExtra(FileActivity.EXTRA_ACCOUNT, download.getAccount());
         showDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
-        
+
         mNotificationBuilder.setContentIntent(PendingIntent.getActivity(
-            this, (int) System.currentTimeMillis(), showDetailsIntent, 0
+                this, (int) System.currentTimeMillis(), showDetailsIntent, 0
         ));
 
         mNotificationManager.notify(R.string.downloader_download_in_progress_ticker, mNotificationBuilder.build());
     }
 
-    
+
     /**
      * Callback method to update the progress bar in the status notification.
      */
     @Override
-    public void onTransferProgress(long progressRate, long totalTransferredSoFar, long totalToTransfer, String filePath)
-    {
-        int percent = (int)(100.0*((double)totalTransferredSoFar)/((double)totalToTransfer));
+    public void onTransferProgress(long progressRate, long totalTransferredSoFar, long totalToTransfer, String filePath) {
+        int percent = (int) (100.0 * ((double) totalTransferredSoFar) / ((double) totalToTransfer));
         if (percent != mLastPercent) {
             mNotificationBuilder.setProgress(100, percent, totalToTransfer < 0);
             String fileName = filePath.substring(filePath.lastIndexOf(FileUtils.PATH_SEPARATOR) + 1);
@@ -502,36 +580,36 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis
         }
         mLastPercent = percent;
     }
-    
-    
+
+
     /**
      * Updates the status notification with the result of a download operation.
-     * 
-     * @param downloadResult    Result of the download operation.
-     * @param download          Finished download operation
+     *
+     * @param downloadResult Result of the download operation.
+     * @param download       Finished download operation
      */
     private void notifyDownloadResult(DownloadFileOperation download, RemoteOperationResult downloadResult) {
         mNotificationManager.cancel(R.string.downloader_download_in_progress_ticker);
         if (!downloadResult.isCancelled()) {
-            int tickerId = (downloadResult.isSuccess()) ? R.string.downloader_download_succeeded_ticker : 
-                R.string.downloader_download_failed_ticker;
-            
+            int tickerId = (downloadResult.isSuccess()) ? R.string.downloader_download_succeeded_ticker :
+                    R.string.downloader_download_failed_ticker;
+
             boolean needsToUpdateCredentials = (
                     downloadResult.getCode() == ResultCode.UNAUTHORIZED ||
-                    downloadResult.isIdPRedirection()
+                            downloadResult.isIdPRedirection()
             );
-            tickerId = (needsToUpdateCredentials) ? 
+            tickerId = (needsToUpdateCredentials) ?
                     R.string.downloader_download_failed_credentials_error : tickerId;
-            
+
             mNotificationBuilder
-            .setTicker(getString(tickerId))
-            .setContentTitle(getString(tickerId))
-            .setAutoCancel(true)
-            .setOngoing(false)
-            .setProgress(0, 0, false);
-            
+                    .setTicker(getString(tickerId))
+                    .setContentTitle(getString(tickerId))
+                    .setAutoCancel(true)
+                    .setOngoing(false)
+                    .setProgress(0, 0, false);
+
             if (needsToUpdateCredentials) {
-                
+
                 // let the user update credentials with one click
                 Intent updateAccountCredentials = new Intent(this, AuthenticatorActivity.class);
                 updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, download.getAccount());
@@ -542,41 +620,41 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis
                 updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
                 updateAccountCredentials.addFlags(Intent.FLAG_FROM_BACKGROUND);
                 mNotificationBuilder
-                    .setContentIntent(PendingIntent.getActivity(
-                        this, (int) System.currentTimeMillis(), updateAccountCredentials, PendingIntent.FLAG_ONE_SHOT));
-                
+                        .setContentIntent(PendingIntent.getActivity(
+                                this, (int) System.currentTimeMillis(), updateAccountCredentials, PendingIntent.FLAG_ONE_SHOT));
+
             } else {
                 // TODO put something smart in showDetailsIntent
-                Intent   showDetailsIntent = new Intent();
+                Intent showDetailsIntent = new Intent();
                 mNotificationBuilder
-                    .setContentIntent(PendingIntent.getActivity(
-                        this, (int) System.currentTimeMillis(), showDetailsIntent, 0));
+                        .setContentIntent(PendingIntent.getActivity(
+                                this, (int) System.currentTimeMillis(), showDetailsIntent, 0));
             }
-            
+
             mNotificationBuilder.setContentText(
                     ErrorMessageAdapter.getErrorCauseMessage(downloadResult, download, getResources())
             );
             mNotificationManager.notify(tickerId, mNotificationBuilder.build());
-            
+
             // Remove success notification
-            if (downloadResult.isSuccess()) {   
+            if (downloadResult.isSuccess()) {
                 // Sleep 2 seconds, so show the notification before remove it
                 NotificationDelayer.cancelWithDelay(
-                        mNotificationManager, 
-                        R.string.downloader_download_succeeded_ticker, 
+                        mNotificationManager,
+                        R.string.downloader_download_succeeded_ticker,
                         2000);
             }
-                
+
         }
     }
-    
-    
+
+
     /**
      * Sends a broadcast when a download finishes in order to the interested activities can update their view
-     * 
-     * @param download                  Finished download operation
-     * @param downloadResult            Result of the download operation
-     * @param unlinkedFromRemotePath    Path in the downloads tree where the download was unlinked from
+     *
+     * @param download               Finished download operation
+     * @param downloadResult         Result of the download operation
+     * @param unlinkedFromRemotePath Path in the downloads tree where the download was unlinked from
      */
     private void sendBroadcastDownloadFinished(
             DownloadFileOperation download,
@@ -592,13 +670,13 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis
         }
         sendStickyBroadcast(end);
     }
-    
-    
+
+
     /**
      * Sends a broadcast when a new download is added to the queue.
-     * 
-     * @param download              Added download operation
-     * @param linkedToRemotePath    Path in the downloads tree where the download was linked to
+     *
+     * @param download           Added download operation
+     * @param linkedToRemotePath Path in the downloads tree where the download was linked to
      */
     private void sendBroadcastNewDownload(DownloadFileOperation download, String linkedToRemotePath) {
         Intent added = new Intent(getDownloadAddedMessage());
@@ -609,4 +687,13 @@ public class FileDownloader extends Service implements OnDatatransferProgressLis
         sendStickyBroadcast(added);
     }
 
+    /**
+     * Remove downloads of an account
+     *
+     * @param account       Downloads account to remove
+     */
+    private void cancelDownloadsForAccount(Account account) {
+        // Cancel pending downloads
+        mPendingDownloads.remove(account);
+    }
 }
index 386f185..851e343 100644 (file)
@@ -1,6 +1,8 @@
-/* ownCloud Android client application
+/**
+ *   ownCloud Android client application
+ *
  *   Copyright (C) 2012 Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
+ *   Copyright (C) 2012-2015 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,
@@ -31,6 +33,7 @@ import java.util.concurrent.ConcurrentMap;
 import android.accounts.Account;
 import android.accounts.AccountManager;
 import android.accounts.AccountsException;
+import android.accounts.OnAccountsUpdateListener;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.app.Service;
@@ -76,8 +79,8 @@ import com.owncloud.android.utils.ErrorMessageAdapter;
 import com.owncloud.android.utils.UriUtils;
 
 
-
-public class FileUploader extends Service implements OnDatatransferProgressListener {
+public class FileUploader extends Service
+        implements OnDatatransferProgressListener, OnAccountsUpdateListener {
 
     private static final String UPLOAD_FINISH_MESSAGE = "UPLOAD_FINISH";
     public static final String EXTRA_UPLOAD_RESULT = "RESULT";
@@ -124,14 +127,14 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
     private static final String MIME_TYPE_PDF = "application/pdf";
     private static final String FILE_EXTENSION_PDF = ".pdf";
 
-    
+
     public static String getUploadFinishMessage() {
         return FileUploader.class.getName().toString() + UPLOAD_FINISH_MESSAGE;
     }
-    
+
     /**
      * Builds a key for mPendingUploads from the account and file to upload
-     * 
+     *
      * @param account   Account where the file to upload is stored
      * @param file      File to upload
      */
@@ -145,7 +148,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
 
     /**
      * Checks if an ownCloud server version should support chunked uploads.
-     * 
+     *
      * @param version OwnCloud version instance corresponding to an ownCloud
      *            server.
      * @return 'True' if the ownCloud server with version supports chunked
@@ -161,24 +164,50 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
     @Override
     public void onCreate() {
         super.onCreate();
-        Log_OC.i(TAG, "mPendingUploads size:" + mPendingUploads.size());
+        Log_OC.d(TAG, "Creating service");
         mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
         HandlerThread thread = new HandlerThread("FileUploaderThread", Process.THREAD_PRIORITY_BACKGROUND);
         thread.start();
         mServiceLooper = thread.getLooper();
         mServiceHandler = new ServiceHandler(mServiceLooper, this);
         mBinder = new FileUploaderBinder();
+
+        // add AccountsUpdatedListener
+        AccountManager am = AccountManager.get(getApplicationContext());
+        am.addOnAccountsUpdatedListener(this, null, false);
     }
 
     /**
+     * Service clean up
+     */
+    @Override
+    public void onDestroy() {
+        Log_OC.v(TAG, "Destroying service" );
+        mBinder = null;
+        mServiceHandler = null;
+        mServiceLooper.quit();
+        mServiceLooper = null;
+        mNotificationManager = null;
+
+        // remove AccountsUpdatedListener
+        AccountManager am = AccountManager.get(getApplicationContext());
+        am.removeOnAccountsUpdatedListener(this);
+
+        super.onDestroy();
+    }
+
+
+    /**
      * Entry point to add one or several files to the queue of uploads.
-     * 
+     *
      * New uploads are added calling to startService(), resulting in a call to
      * this method. This ensures the service will keep on working although the
      * caller activity goes away.
      */
     @Override
     public int onStartCommand(Intent intent, int flags, int startId) {
+        Log_OC.d(TAG, "Starting command with id " + startId);
+
         if (!intent.hasExtra(KEY_ACCOUNT) || !intent.hasExtra(KEY_UPLOAD_TYPE)
                 || !(intent.hasExtra(KEY_LOCAL_FILE) || intent.hasExtra(KEY_FILE))) {
             Log_OC.e(TAG, "Not enough information provided in intent");
@@ -229,7 +258,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
         boolean forceOverwrite = intent.getBooleanExtra(KEY_FORCE_OVERWRITE, false);
         boolean isInstant = intent.getBooleanExtra(KEY_INSTANT_UPLOAD, false);
         int localAction = intent.getIntExtra(KEY_LOCAL_BEHAVIOUR, LOCAL_BEHAVIOUR_COPY);
-        
+
         if (intent.hasExtra(KEY_FILE) && files == null) {
             Log_OC.e(TAG, "Incorrect array for OCFiles provided in upload intent");
             return Service.START_NOT_STICKY;
@@ -262,7 +291,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
         AccountManager aMgr = AccountManager.get(this);
         String version = aMgr.getUserData(account, Constants.KEY_OC_VERSION);
         OwnCloudVersion ocv = new OwnCloudVersion(version);
-        
+
         boolean chunked = FileUploader.chunkedUploadIsSupported(ocv);
         AbstractList<String> requestedUploads = new Vector<String>();
         String uploadKey = null;
@@ -270,7 +299,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
         try {
             for (int i = 0; i < files.length; i++) {
                 uploadKey = buildRemoteName(account, files[i].getRemotePath());
-                newUpload = new UploadFileOperation(account, files[i], chunked, isInstant, forceOverwrite, localAction, 
+                newUpload = new UploadFileOperation(account, files[i], chunked, isInstant, forceOverwrite, localAction,
                         getApplicationContext());
                 if (isInstant) {
                     newUpload.setRemoteFolderToBeCreated();
@@ -309,7 +338,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
     /**
      * Provides a binder object that clients can use to perform operations on
      * the queue of uploads, excepting the addition of new files.
-     * 
+     *
      * Implemented to perform cancellation, pause and resume of existing
      * uploads.
      */
@@ -317,7 +346,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
     public IBinder onBind(Intent arg0) {
         return mBinder;
     }
-    
+
     /**
      * Called when ALL the bound clients were onbound.
      */
@@ -326,24 +355,33 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
         ((FileUploaderBinder)mBinder).clearListeners();
         return false;   // not accepting rebinding (default behaviour)
     }
-    
+
+    @Override
+    public void onAccountsUpdated(Account[] accounts) {
+        // Review current upload, and cancel it if its account doen't exist
+        if (mCurrentUpload != null &&
+                !AccountUtils.exists(mCurrentUpload.getAccount(), getApplicationContext())) {
+            mCurrentUpload.cancel();
+        }
+        // The rest of uploads are cancelled when they try to start
+    }
 
     /**
      * Binder to let client components to perform operations on the queue of
      * uploads.
-     * 
+     *
      * It provides by itself the available operations.
      */
     public class FileUploaderBinder extends Binder implements OnDatatransferProgressListener {
-        
-        /** 
+
+        /**
          * Map of listeners that will be reported about progress of uploads from a {@link FileUploaderBinder} instance 
          */
         private Map<String, OnDatatransferProgressListener> mBoundListeners = new HashMap<String, OnDatatransferProgressListener>();
-        
+
         /**
          * Cancels a pending or current upload of a remote file.
-         * 
+         *
          * @param account Owncloud account where the remote file will be stored.
          * @param file A file in the queue of pending uploads
          */
@@ -356,22 +394,35 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
                 upload.cancel();
             }
         }
-        
-        
-        
+
+        /**
+         * Cancels a pending or current upload for an account
+         *
+         * @param account Owncloud accountName where the remote file will be stored.
+         */
+        public void cancel(Account account) {
+            Log_OC.d(TAG, "Account= " + account.name);
+
+            if (mCurrentUpload != null) {
+                Log_OC.d(TAG, "Current Upload Account= " + mCurrentUpload.getAccount().name);
+                if (mCurrentUpload.getAccount().name.equals(account.name)) {
+                    mCurrentUpload.cancel();
+                }
+            }
+            // Cancel pending uploads
+            cancelUploadForAccount(account.name);
+        }
+
         public void clearListeners() {
             mBoundListeners.clear();
         }
 
-
-        
-        
         /**
          * Returns True when the file described by 'file' is being uploaded to
          * the ownCloud account 'account' or waiting for it
-         * 
+         *
          * If 'file' is a directory, returns 'true' if some of its descendant files is uploading or waiting to upload. 
-         * 
+         *
          * @param account   ownCloud account where the remote file will be stored.
          * @param file      A file that could be in the queue of pending uploads
          */
@@ -397,7 +448,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
 
         /**
          * Adds a listener interested in the progress of the upload for a concrete file.
-         * 
+         *
          * @param listener      Object to notify about progress of transfer.    
          * @param account       ownCloud account holding the file of interest.
          * @param file          {@link OCFile} of interest for listener.
@@ -407,12 +458,12 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
             String targetKey = buildRemoteName(account, file);
             mBoundListeners.put(targetKey, listener);
         }
-        
-        
-        
+
+
+
         /**
          * Removes a listener interested in the progress of the upload for a concrete file.
-         * 
+         *
          * @param listener      Object to notify about progress of transfer.    
          * @param account       ownCloud account holding the file of interest.
          * @param file          {@link OCFile} of interest for listener.
@@ -428,20 +479,30 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
 
         @Override
         public void onTransferProgress(long progressRate, long totalTransferredSoFar, long totalToTransfer,
-                String fileName) {
+                                       String fileName) {
             String key = buildRemoteName(mCurrentUpload.getAccount(), mCurrentUpload.getFile());
             OnDatatransferProgressListener boundListener = mBoundListeners.get(key);
             if (boundListener != null) {
                 boundListener.onTransferProgress(progressRate, totalTransferredSoFar, totalToTransfer, fileName);
             }
         }
-        
+
+        /**
+         * Review uploads and cancel it if its account doesn't exist
+         */
+        public void checkAccountOfCurrentUpload() {
+            if (mCurrentUpload != null &&
+                    !AccountUtils.exists(mCurrentUpload.getAccount(), getApplicationContext())) {
+                mCurrentUpload.cancel();
+            }
+            // The rest of uploads are cancelled when they try to start
+        }
     }
 
     /**
      * Upload worker. Performs the pending uploads in the order they were
      * requested.
-     * 
+     *
      * Created with the Looper of a new thread, started in
      * {@link FileUploader#onCreate()}.
      */
@@ -467,13 +528,14 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
                     mService.uploadFile(it.next());
                 }
             }
+            Log_OC.d(TAG, "Stopping command after id " + msg.arg1);
             mService.stopSelf(msg.arg1);
         }
     }
 
     /**
      * Core upload method: sends the file(s) to upload
-     * 
+     *
      * @param uploadKey Key to access the upload to perform, contained in
      *            mPendingUploads
      */
@@ -485,63 +547,73 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
 
         if (mCurrentUpload != null) {
 
-            notifyUploadStart(mCurrentUpload);
+            // Detect if the account exists
+            if (AccountUtils.exists(mCurrentUpload.getAccount(), getApplicationContext())) {
+                Log_OC.d(TAG, "Account " + mCurrentUpload.getAccount().name + " exists");
 
-            RemoteOperationResult uploadResult = null, grantResult = 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());
-                    OwnCloudAccount ocAccount = new OwnCloudAccount(mLastAccount, this);
-                    mUploadClient = OwnCloudClientManagerFactory.getDefaultSingleton().
-                            getClientFor(ocAccount, this);
-                }
-                
-                /// check the existence of the parent folder for the file to upload
-                String remoteParentPath = new File(mCurrentUpload.getRemotePath()).getParent();
-                remoteParentPath = remoteParentPath.endsWith(OCFile.PATH_SEPARATOR) ? remoteParentPath : remoteParentPath + OCFile.PATH_SEPARATOR;
-                grantResult = grantFolderExistence(remoteParentPath);
-            
-                /// perform the upload
-                if (grantResult.isSuccess()) {
-                    OCFile parent = mStorageManager.getFileByPath(remoteParentPath);
-                    mCurrentUpload.getFile().setParentId(parent.getFileId());
-                    uploadResult = mCurrentUpload.execute(mUploadClient);
-                    if (uploadResult.isSuccess()) {
-                        saveUploadedFile();
+                notifyUploadStart(mCurrentUpload);
+
+                RemoteOperationResult uploadResult = null, grantResult = 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());
+                        OwnCloudAccount ocAccount = new OwnCloudAccount(mLastAccount, this);
+                        mUploadClient = OwnCloudClientManagerFactory.getDefaultSingleton().
+                                getClientFor(ocAccount, this);
+                    }
+
+                    /// check the existence of the parent folder for the file to upload
+                    String remoteParentPath = new File(mCurrentUpload.getRemotePath()).getParent();
+                    remoteParentPath = remoteParentPath.endsWith(OCFile.PATH_SEPARATOR) ?
+                            remoteParentPath : remoteParentPath + OCFile.PATH_SEPARATOR;
+                    grantResult = grantFolderExistence(remoteParentPath);
+
+                    /// perform the upload
+                    if (grantResult.isSuccess()) {
+                        OCFile parent = mStorageManager.getFileByPath(remoteParentPath);
+                        mCurrentUpload.getFile().setParentId(parent.getFileId());
+                        uploadResult = mCurrentUpload.execute(mUploadClient);
+                        if (uploadResult.isSuccess()) {
+                            saveUploadedFile();
+                        }
+                    } else {
+                        uploadResult = grantResult;
+                    }
+
+                } 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.");
+                    }
+                    if (uploadResult.isException()) {
+                        // enforce the creation of a new client object for next uploads; this grant that a new socket will
+                        // be created in the future if the current exception is due to an abrupt lose of network connection
+                        mUploadClient = null;
                     }
-                } else {
-                    uploadResult = grantResult;
-                }
-                
-            } 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.");
-                }
-                if (uploadResult.isException()) {
-                    // enforce the creation of a new client object for next uploads; this grant that a new socket will 
-                    // be created in the future if the current exception is due to an abrupt lose of network connection
-                    mUploadClient = null;
                 }
-            }
-            
-            /// notify result
-            
-            notifyUploadResult(uploadResult, mCurrentUpload);
-            sendFinalBroadcast(mCurrentUpload, uploadResult);
 
+                /// notify result
+                notifyUploadResult(uploadResult, mCurrentUpload);
+                sendFinalBroadcast(mCurrentUpload, uploadResult);
+
+            } else {
+                // Cancel the transfer
+                Log_OC.d(TAG, "Account " + mCurrentUpload.getAccount().toString() + " doesn't exist");
+                cancelUploadForAccount(mCurrentUpload.getAccount().name);
+
+            }
         }
 
     }
@@ -549,17 +621,18 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
     /**
      * Checks the existence of the folder where the current file will be uploaded both in the remote server 
      * and in the local database.
-     * 
+     *
      * If the upload is set to enforce the creation of the folder, the method tries to create it both remote
      * and locally.
-     *  
+     *
      *  @param  pathToGrant     Full remote path whose existence will be granted.
      *  @return  An {@link OCFile} instance corresponding to the folder where the file will be uploaded.
      */
     private RemoteOperationResult grantFolderExistence(String pathToGrant) {
         RemoteOperation operation = new ExistenceCheckRemoteOperation(pathToGrant, this, false);
         RemoteOperationResult result = operation.execute(mUploadClient);
-        if (!result.isSuccess() && result.getCode() == ResultCode.FILE_NOT_FOUND && mCurrentUpload.isRemoteFolderToBeCreated()) {
+        if (!result.isSuccess() && result.getCode() == ResultCode.FILE_NOT_FOUND &&
+                mCurrentUpload.isRemoteFolderToBeCreated()) {
             SyncOperation syncOp = new CreateFolderOperation( pathToGrant, true);
             result = syncOp.execute(mUploadClient, mStorageManager);
         }
@@ -577,10 +650,11 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
         return result;
     }
 
-    
+
     private OCFile createLocalFolder(String remotePath) {
         String parentPath = new File(remotePath).getParent();
-        parentPath = parentPath.endsWith(OCFile.PATH_SEPARATOR) ? parentPath : parentPath + OCFile.PATH_SEPARATOR;
+        parentPath = parentPath.endsWith(OCFile.PATH_SEPARATOR) ?
+                parentPath : parentPath + OCFile.PATH_SEPARATOR;
         OCFile parent = mStorageManager.getFileByPath(parentPath);
         if (parent == null) {
             parent = createLocalFolder(parentPath);
@@ -594,15 +668,15 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
         }
         return null;
     }
-    
+
 
     /**
      * Saves a OC File after a successful upload.
-     * 
+     *
      * A PROPFIND is necessary to keep the props in the local database
      * synchronized with the server, specially the modification time and Etag
      * (where available)
-     * 
+     *
      * TODO refactor this ugly thing
      */
     private void saveUploadedFile() {
@@ -621,7 +695,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
             updateOCFile(file, (RemoteFile) result.getData().get(0));
             file.setLastSyncDateForProperties(syncDate);
         }
-        
+
         // / maybe this would be better as part of UploadFileOperation... or
         // maybe all this method
         if (mCurrentUpload.wasRenamed()) {
@@ -631,8 +705,8 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
                 mStorageManager.saveFile(oldFile);
 
             } // else: it was just an automatic renaming due to a name
-              // coincidence; nothing else is needed, the storagePath is right
-              // in the instance returned by mCurrentUpload.getFile()
+            // coincidence; nothing else is needed, the storagePath is right
+            // in the instance returned by mCurrentUpload.getFile()
         }
         file.setNeedsUpdateThumbnail(true);
         mStorageManager.saveFile(file);
@@ -649,7 +723,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
     }
 
     private OCFile obtainNewOCFileToUpload(String remotePath, String localPath, String mimeType,
-            FileDataStorageManager storageManager) {
+                                           FileDataStorageManager storageManager) {
 
         // MIME type
         if (mimeType == null || mimeType.length() <= 0) {
@@ -679,7 +753,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
             newFile.setFileLength(localFile.length());
             newFile.setLastSyncDateForData(localFile.lastModified());
         } // don't worry about not assigning size, the problems with localPath
-          // are checked when the UploadFileOperation instance is created
+        // are checked when the UploadFileOperation instance is created
 
 
         newFile.setMimetype(mimeType);
@@ -689,13 +763,13 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
 
     /**
      * Creates a status notification to show the upload progress
-     * 
+     *
      * @param upload Upload operation starting.
      */
     private void notifyUploadStart(UploadFileOperation upload) {
         // / create status notification with a progress bar
         mLastPercent = 0;
-        mNotificationBuilder = 
+        mNotificationBuilder =
                 NotificationBuilderWithProgressBar.newNotificationBuilderWithProgressBar(this);
         mNotificationBuilder
                 .setOngoing(true)
@@ -712,7 +786,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
         showDetailsIntent.putExtra(FileActivity.EXTRA_ACCOUNT, upload.getAccount());
         showDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
         mNotificationBuilder.setContentIntent(PendingIntent.getActivity(
-            this, (int) System.currentTimeMillis(), showDetailsIntent, 0
+                this, (int) System.currentTimeMillis(), showDetailsIntent, 0
         ));
 
         mNotificationManager.notify(R.string.uploader_upload_in_progress_ticker, mNotificationBuilder.build());
@@ -736,7 +810,7 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
 
     /**
      * Updates the status notification with the result of an upload operation.
-     * 
+     *
      * @param uploadResult Result of the upload operation.
      * @param upload Finished upload operation
      */
@@ -745,33 +819,33 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
         Log_OC.d(TAG, "NotifyUploadResult with resultCode: " + uploadResult.getCode());
         // / cancelled operation or success -> silent removal of progress notification
         mNotificationManager.cancel(R.string.uploader_upload_in_progress_ticker);
-        
+
         // Show the result: success or fail notification
         if (!uploadResult.isCancelled()) {
-            int tickerId = (uploadResult.isSuccess()) ? R.string.uploader_upload_succeeded_ticker : 
-                R.string.uploader_upload_failed_ticker;
-            
+            int tickerId = (uploadResult.isSuccess()) ? R.string.uploader_upload_succeeded_ticker :
+                    R.string.uploader_upload_failed_ticker;
+
             String content = null;
 
             // check credentials error
             boolean needsToUpdateCredentials = (
-                    uploadResult.getCode() == ResultCode.UNAUTHORIZED || 
-                    uploadResult.isIdPRedirection()
+                    uploadResult.getCode() == ResultCode.UNAUTHORIZED ||
+                            uploadResult.isIdPRedirection()
             );
-            tickerId = (needsToUpdateCredentials) ? 
+            tickerId = (needsToUpdateCredentials) ?
                     R.string.uploader_upload_failed_credentials_error : tickerId;
 
             mNotificationBuilder
-            .setTicker(getString(tickerId))
-            .setContentTitle(getString(tickerId))
-            .setAutoCancel(true)
-            .setOngoing(false)
-            .setProgress(0, 0, false);
-            
+                    .setTicker(getString(tickerId))
+                    .setContentTitle(getString(tickerId))
+                    .setAutoCancel(true)
+                    .setOngoing(false)
+                    .setProgress(0, 0, false);
+
             content =  ErrorMessageAdapter.getErrorCauseMessage(
                     uploadResult, upload, getResources()
             );
-            
+
             if (needsToUpdateCredentials) {
                 // let the user update credentials with one click
                 Intent updateAccountCredentials = new Intent(this, AuthenticatorActivity.class);
@@ -779,24 +853,24 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
                         AuthenticatorActivity.EXTRA_ACCOUNT, upload.getAccount()
                 );
                 updateAccountCredentials.putExtra(
-                        AuthenticatorActivity.EXTRA_ACTION, 
+                        AuthenticatorActivity.EXTRA_ACTION,
                         AuthenticatorActivity.ACTION_UPDATE_EXPIRED_TOKEN
                 );
                 updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                 updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
                 updateAccountCredentials.addFlags(Intent.FLAG_FROM_BACKGROUND);
                 mNotificationBuilder.setContentIntent(PendingIntent.getActivity(
-                    this, 
-                    (int) System.currentTimeMillis(), 
-                    updateAccountCredentials, 
-                    PendingIntent.FLAG_ONE_SHOT
+                        this,
+                        (int) System.currentTimeMillis(),
+                        updateAccountCredentials,
+                        PendingIntent.FLAG_ONE_SHOT
                 ));
-                
-                mUploadClient = null;   
-                    // grant that future retries on the same account will get the fresh credentials
+
+                mUploadClient = null;
+                // grant that future retries on the same account will get the fresh credentials
             } else {
                 mNotificationBuilder.setContentText(content);
-    
+
                 if (upload.isInstant()) {
                     DbHandler db = null;
                     try {
@@ -807,12 +881,12 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
                         if (uploadResult.getCode() == ResultCode.QUOTA_EXCEEDED) {
                             //message = getString(R.string.failed_upload_quota_exceeded_text);
                             if (db.updateFileState(
-                                    upload.getOriginalStoragePath(), 
+                                    upload.getOriginalStoragePath(),
                                     DbHandler.UPLOAD_STATUS_UPLOAD_FAILED,
                                     message) == 0) {
                                 db.putFileForLater(
-                                        upload.getOriginalStoragePath(), 
-                                        upload.getAccount().name, 
+                                        upload.getOriginalStoragePath(),
+                                        upload.getAccount().name,
                                         message
                                 );
                             }
@@ -824,22 +898,22 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
                     }
                 }
             }
-            
+
             mNotificationBuilder.setContentText(content);
             mNotificationManager.notify(tickerId, mNotificationBuilder.build());
-            
+
             if (uploadResult.isSuccess()) {
-                
+
                 DbHandler db = new DbHandler(this.getBaseContext());
                 db.removeIUPendingFile(mCurrentUpload.getOriginalStoragePath());
                 db.close();
 
                 // remove success notification, with a delay of 2 seconds
                 NotificationDelayer.cancelWithDelay(
-                        mNotificationManager, 
-                        R.string.uploader_upload_succeeded_ticker, 
+                        mNotificationManager,
+                        R.string.uploader_upload_succeeded_ticker,
                         2000);
-                
+
             }
         }
     }
@@ -847,17 +921,17 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
     /**
      * Sends a broadcast in order to the interested activities can update their
      * view
-     * 
+     *
      * @param upload Finished upload operation
      * @param uploadResult Result of the upload operation
      */
     private void sendFinalBroadcast(UploadFileOperation upload, RemoteOperationResult uploadResult) {
         Intent end = new Intent(getUploadFinishMessage());
         end.putExtra(EXTRA_REMOTE_PATH, upload.getRemotePath()); // real remote
-                                                                 // path, after
-                                                                 // possible
-                                                                 // automatic
-                                                                 // renaming
+        // path, after
+        // possible
+        // automatic
+        // renaming
         if (upload.wasRenamed()) {
             end.putExtra(EXTRA_OLD_REMOTE_PATH, upload.getOldFile().getRemotePath());
         }
@@ -875,9 +949,27 @@ public class FileUploader extends Service implements OnDatatransferProgressListe
      * @return true if is needed to add the pdf file extension to the file
      */
     private boolean isPdfFileFromContentProviderWithoutExtension(String localPath, String mimeType) {
-        return localPath.startsWith(UriUtils.URI_CONTENT_SCHEME) && 
-                mimeType.equals(MIME_TYPE_PDF) && 
+        return localPath.startsWith(UriUtils.URI_CONTENT_SCHEME) &&
+                mimeType.equals(MIME_TYPE_PDF) &&
                 !localPath.endsWith(FILE_EXTENSION_PDF);
     }
 
+    /**
+     * Remove uploads of an account
+     * @param accountName
+     */
+    private void cancelUploadForAccount(String accountName){
+        // this can be slow if there are many uploads :(
+        Iterator<String> it = mPendingUploads.keySet().iterator();
+        Log_OC.d(TAG, "Number of pending updloads= "  + mPendingUploads.size());
+        while (it.hasNext()) {
+            String key = it.next();
+            Log_OC.d(TAG, "mPendingUploads CANCELLED " + key);
+            if (key.startsWith(accountName)) {
+                synchronized (mPendingUploads) {
+                    mPendingUploads.remove(key);
+                }
+            }
+        }
+    }
 }
index e2e9cb8..4c1ac7b 100644 (file)
@@ -1,4 +1,7 @@
-/* ownCloud Android client application
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
  *   Copyright (C) 2015 ownCloud Inc.
  *
  *   This program is free software: you can redistribute it and/or modify
@@ -21,6 +24,7 @@ import android.accounts.Account;
 import android.util.Pair;
 
 import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.lib.common.utils.Log_OC;
 
 import java.io.File;
 import java.util.HashSet;
@@ -35,8 +39,6 @@ import java.util.concurrent.ConcurrentMap;
  *  A map provides the indexation based in hashing.
  *
  *  A tree is created per account.
- *
- * @author David A. Velasco
  */
 public class IndexedForest<V> {
 
@@ -211,6 +213,21 @@ public class IndexedForest<V> {
 
 
     /**
+     * Remove the elements that contains account as a part of its key
+     * @param account
+     */
+    public void remove(Account account){
+        Iterator<String> it = mMap.keySet().iterator();
+        while (it.hasNext()) {
+            String key = it.next();
+            Log_OC.d("IndexedForest", "Number of pending downloads= "  + mMap.size());
+            if (key.startsWith(account.name)) {
+                mMap.remove(key);
+            }
+        }
+    }
+
+    /**
      * Builds a key to index files
      *
      * @param account       Account where the file to download is stored
@@ -220,6 +237,4 @@ public class IndexedForest<V> {
         return account.name + remotePath;
     }
 
-
-
 }
index b6ee1ac..f2ed3bb 100644 (file)
@@ -1,6 +1,8 @@
-/* ownCloud Android client application
+/**
+ *   ownCloud Android client application
+ *
  *   Copyright (C) 2012 Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
+ *   Copyright (C) 2015 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,
index b257bd3..653943b 100644 (file)
@@ -1,6 +1,8 @@
-/* ownCloud Android client application
- * 
- *   Copyright (C) 2012-2013  ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
+ *   Copyright (C) 2015 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,
@@ -51,8 +53,6 @@ import com.owncloud.android.R;
  * 
  * It synchronizes itself with the state of the 
  * {@link MediaPlayer}.
- * 
- * @author David A. Velasco
  */
 
 public class MediaControlView extends FrameLayout /* implements OnLayoutChangeListener, OnTouchListener */ implements OnClickListener, OnSeekBarChangeListener {
index 52daa04..e53c635 100644 (file)
@@ -1,5 +1,8 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2013 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
+ *   Copyright (C) 2015 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,
@@ -49,8 +52,6 @@ import com.owncloud.android.ui.activity.FileDisplayActivity;
  * 
  * Waits for Intents which signal the service to perform specific operations: Play, Pause,
  * Rewind, etc.
- * 
- * @author David A. Velasco
  */
 public class MediaService extends Service implements OnCompletionListener, OnPreparedListener,
                 OnErrorListener, AudioManager.OnAudioFocusChangeListener {
index 1b56ec0..95bf520 100644 (file)
@@ -1,5 +1,8 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2013 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
+ *   Copyright (C) 2015 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,
@@ -34,8 +37,6 @@ import android.widget.MediaController;
  * 
  *  Provides the operations of {@link MediaController.MediaPlayerControl}, and an extra method to check if
  *  an {@link OCFile} instance is handled by the MediaService.
- *  
- *  @author David A. Velasco
  */
 public class MediaServiceBinder extends Binder implements MediaController.MediaPlayerControl {
 
index 63ddf63..c71b35f 100644 (file)
@@ -1,5 +1,8 @@
-/* ownCloud Android client application
- *   Copyright (C) 2014 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
+ *   Copyright (C) 2015 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,
@@ -31,8 +34,6 @@ import android.widget.RemoteViews;
  * a progress bar is available in every Android version, because 
  * {@link NotificationCompat.Builder#setProgress(int, int, boolean)} has no
  * real effect for Android < 4.0
- * 
- * @author David A. Velasco
  */
 public class NotificationBuilderWithProgressBar extends NotificationCompat.Builder {
 
index aeefe12..ab1399f 100644 (file)
@@ -1,3 +1,22 @@
+/**
+ *   ownCloud Android client application
+ *
+ *   Copyright (C) 2015 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.notifications;
 
 import java.util.Random;
index 4df8b3d..b3c17f1 100644 (file)
@@ -1,5 +1,9 @@
-/* ownCloud Android client application
- *   Copyright (C) 2014 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
+ *   @author masensio
+ *   Copyright (C) 2015 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,
@@ -31,9 +35,6 @@ import com.owncloud.android.utils.FileStorageUtils;
 /**
  * Access to remote operation performing the creation of a new folder in the ownCloud server.
  * Save the new folder in Database
- * 
- * @author David A. Velasco 
- * @author masensio
  */
 public class CreateFolderOperation extends SyncOperation implements OnRemoteOperationListener{
     
index fc44f53..70d6bf7 100644 (file)
@@ -1,5 +1,8 @@
-/* ownCloud Android client application
- *   Copyright (C) 2014 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   @author masensio
+ *   Copyright (C) 2015 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,
@@ -19,9 +22,6 @@ package com.owncloud.android.operations;
 
 /**
  * Creates a new share from a given file
- * 
- * @author masensio
- *
  */
 
 import android.content.Context;
@@ -44,7 +44,6 @@ import com.owncloud.android.operations.common.SyncOperation;
 public class CreateShareOperation extends SyncOperation {
 
     private static final String TAG = CreateShareOperation.class.getSimpleName();
-    
 
     protected FileDataStorageManager mStorageManager;
 
@@ -76,8 +75,9 @@ public class CreateShareOperation extends SyncOperation {
      *                      To obtain combinations, add the desired values together.  
      *                      For instance, for Re-Share, delete, read, update, add 16+8+2+1 = 27.
      */
-    public CreateShareOperation(Context context, String path, ShareType shareType, String shareWith, boolean publicUpload,
-            String password, int permissions, Intent sendIntent) {
+    public CreateShareOperation(Context context, String path, ShareType shareType, String shareWith,
+                                boolean publicUpload, String password, int permissions,
+                                Intent sendIntent) {
 
         mContext = context;
         mPath = path;
@@ -98,7 +98,8 @@ public class CreateShareOperation extends SyncOperation {
         RemoteOperationResult result = ((GetRemoteSharesForFileOperation)operation).execute(client);
 
         if (!result.isSuccess() || result.getData().size() <= 0) {
-            operation = new CreateRemoteShareOperation(mPath, mShareType, mShareWith, mPublicUpload, mPassword, mPermissions);
+            operation = new CreateRemoteShareOperation(mPath, mShareType, mShareWith, mPublicUpload,
+                    mPassword, mPermissions);
             result = ((CreateRemoteShareOperation)operation).execute(client);
         }
         
@@ -112,7 +113,30 @@ public class CreateShareOperation extends SyncOperation {
         return result;
     }
     
-    
+    public String getPath() {
+        return mPath;
+    }
+
+    public ShareType getShareType() {
+        return mShareType;
+    }
+
+    public String getShareWith() {
+        return mShareWith;
+    }
+
+    public boolean getPublicUpload() {
+        return mPublicUpload;
+    }
+
+    public String getPassword() {
+        return mPassword;
+    }
+
+    public int getPermissions() {
+        return mPermissions;
+    }
+
     public Intent getSendIntent() {
         return mSendIntent;
     }
@@ -134,8 +158,7 @@ public class CreateShareOperation extends SyncOperation {
         if (file!=null) {
             mSendIntent.putExtra(Intent.EXTRA_TEXT, share.getShareLink());
             mSendIntent.putExtra(Intent.EXTRA_SUBJECT, String.format(mContext.getString(R.string.subject_token),
-                    getClient().getCredentials().getUsername(), mContext.getString(R.string.shared_subject_header),
-                    file.getFileName(), mContext.getString(R.string.with_you_subject_header)));
+                    getClient().getCredentials().getUsername(), file.getFileName()));
             file.setPublicLink(share.getShareLink());
             file.setShareByLink(true);
             getStorageManager().saveFile(file);
index 5afc421..9f2827f 100644 (file)
@@ -1,24 +1,20 @@
-/* ownCloud Android Library is available under MIT license
- *   Copyright (C) 2014 ownCloud Inc.
- *   
- *   Permission is hereby granted, free of charge, to any person obtaining a copy
- *   of this software and associated documentation files (the "Software"), to deal
- *   in the Software without restriction, including without limitation the rights
- *   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- *   copies of the Software, and to permit persons to whom the Software is
- *   furnished to do so, subject to the following conditions:
- *   
- *   The above copyright notice and this permission notice shall be included in
- *   all copies or substantial portions of the Software.
- *   
- *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
- *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
- *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 
- *   BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 
- *   ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 
- *   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- *   THE SOFTWARE.
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
+ *   Copyright (C) 2015 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/>.
  *
  */
 
@@ -47,9 +43,7 @@ import android.net.Uri;
  * When successful, the instance of {@link RemoteOperationResult} passed
  * through {@link OnRemoteOperationListener#onRemoteOperationFinish(RemoteOperation, 
  * RemoteOperationResult)} returns in {@link RemoteOperationResult#getData()}
- * a value of {@link AuthenticationMethod}. 
- * 
- * @author David A. Velasco
+ * a value of {@link AuthenticationMethod}.
  */
 public class DetectAuthenticationMethodOperation extends RemoteOperation {
     
index 0a5ff94..78811f8 100644 (file)
@@ -1,5 +1,9 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2013 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
+ *   @author masensio
+ *   Copyright (C) 2015 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,
@@ -38,9 +42,6 @@ import android.webkit.MimeTypeMap;
 
 /**
  * Remote mDownloadOperation performing the download of a file to an ownCloud server
- * 
- * @author David A. Velasco
- * @author masensio
  */
 public class DownloadFileOperation extends RemoteOperation {
     
@@ -177,5 +178,4 @@ public class DownloadFileOperation extends RemoteOperation {
             mDataTransferListeners.remove(listener);
         }
     }
-    
 }
index 9b7cf87..e081d4e 100644 (file)
@@ -1,24 +1,21 @@
-/* ownCloud Android Library is available under MIT license
- *   Copyright (C) 2014 ownCloud Inc.
- *   
- *   Permission is hereby granted, free of charge, to any person obtaining a copy
- *   of this software and associated documentation files (the "Software"), to deal
- *   in the Software without restriction, including without limitation the rights
- *   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- *   copies of the Software, and to permit persons to whom the Software is
- *   furnished to do so, subject to the following conditions:
- *   
- *   The above copyright notice and this permission notice shall be included in
- *   all copies or substantial portions of the Software.
- *   
- *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
- *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
- *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 
- *   BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 
- *   ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 
- *   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- *   THE SOFTWARE.
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
+ *   @author masensio
+ *   Copyright (C) 2015 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/>.
  *
  */
 
@@ -43,9 +40,6 @@ import android.content.Context;
  * 
  * Checks the existence of a configured ownCloud server in the URL, gets its version 
  * and finds out what authentication method is needed to access files in it.
- * 
- * @author David A. Velasco
- * @author masensio
  */
 
 public class GetServerInfoOperation extends RemoteOperation {
index 649437d..06e399e 100644 (file)
@@ -1,5 +1,8 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2013 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   @author masensio
+ *   Copyright (C) 2015 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,
@@ -28,10 +31,7 @@ import com.owncloud.android.lib.resources.shares.GetRemoteSharesForFileOperation
 import com.owncloud.android.operations.common.SyncOperation;
 
 /**
- * Provide a list shares for a specific file.  
- * 
- * @author masensio
- *
+ * Provide a list shares for a specific file.
  */
 public class GetSharesForFileOperation extends SyncOperation {
     
index d096788..fb838b4 100644 (file)
@@ -1,5 +1,9 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2014 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   @author masensio
+ *   @author David A. Velasco
+ *   Copyright (C) 2015 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,
@@ -29,9 +33,6 @@ import com.owncloud.android.operations.common.SyncOperation;
 /**
  * Access to remote operation to get the share files/folders
  * Save the data in Database
- * 
- * @author masensio
- * @author David A. Velasco
  */
 
 public class GetSharesOperation extends SyncOperation {
index 63856c3..3a1103b 100644 (file)
@@ -1,5 +1,8 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2014 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
+ *   Copyright (C) 2015 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,
@@ -29,8 +32,6 @@ import android.accounts.Account;
 
 /**
  * Operation mmoving an {@link OCFile} to a different folder.
- * 
- * @author David A. Velasco
  */
 public class MoveFileOperation extends SyncOperation {
     
index 6f4ff74..918c57b 100644 (file)
@@ -1,3 +1,22 @@
+/**
+ *   ownCloud Android client application
+ *
+ *   Copyright (C) 2015 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 java.util.ArrayList;
index 5371789..8d6cfbb 100644 (file)
@@ -1,5 +1,8 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2014 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
+ *   Copyright (C) 2015 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,
@@ -64,8 +67,6 @@ import com.owncloud.android.utils.FileStorageUtils;
  *  properties, and updates the local database with them.
  *  
  *  Does NOT enter in the child folders to synchronize their contents also.
- * 
- *  @author David A. Velasco
  */
 public class RefreshFolderOperation extends RemoteOperation {
 
index 6bd4e8a..8f7067d 100644 (file)
@@ -1,5 +1,9 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2014 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
+ *   @author masensio
+ *   Copyright (C) 2015 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,
@@ -27,9 +31,6 @@ import com.owncloud.android.operations.common.SyncOperation;
 
 /**
  * Remote operation performing the removal of a remote file or folder in the ownCloud server.
- * 
- * @author David A. Velasco
- * @author masensio
  */
 public class RemoveFileOperation extends SyncOperation {
     
index 2fdc8f1..9726395 100644 (file)
@@ -1,5 +1,9 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2014 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
+ *   @author masensio
+ *   Copyright (C) 2015 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,
@@ -32,9 +36,6 @@ import com.owncloud.android.utils.FileStorageUtils;
 
 /**
  * Remote operation performing the rename of a remote file (or folder?) in the ownCloud server.
- * 
- * @author David A. Velasco
- * @author masensio
  */
 public class RenameFileOperation extends SyncOperation {
     
@@ -51,7 +52,6 @@ public class RenameFileOperation extends SyncOperation {
      * Constructor
      * 
      * @param remotePath            RemotePath of the OCFile instance describing the remote file or folder to rename
-     * @param account               OwnCloud account containing the remote file 
      * @param newName               New name to set as the name of file.
      */
     public RenameFileOperation(String remotePath, String newName) {
@@ -117,7 +117,7 @@ public class RenameFileOperation extends SyncOperation {
 
     private void saveLocalFile() {
         mFile.setFileName(mNewName);
-        
+
         // try to rename the local copy of the file
         if (mFile.isDown()) {
             String oldPath = mFile.getStoragePath();
@@ -129,8 +129,8 @@ public class RenameFileOperation extends SyncOperation {
                 String newPath = parentStoragePath + mNewName;
                 mFile.setStoragePath(newPath);
 
-                // notify MediaScanner about removed file - TODO really works?
-                getStorageManager().triggerMediaScan(oldPath);
+                // notify MediaScanner about removed file
+                getStorageManager().deleteFileInMediaScan(oldPath);
                 // notify to scan about new file
                 getStorageManager().triggerMediaScan(newPath);
             }
index 72cb22b..6f1730e 100644 (file)
@@ -1,6 +1,10 @@
-/* ownCloud Android client application
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
+ *   @author masensio
  *   Copyright (C) 2012 Bartek Przybylski
- *   Copyright (C) 2012-2014 ownCloud Inc.
+ *   Copyright (C) 2015 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,
@@ -36,9 +40,6 @@ import android.content.Intent;
 
 /**
  * Remote operation performing the read of remote file in the ownCloud server.
- * 
- * @author David A. Velasco
- * @author masensio
  */
 
 public class SynchronizeFileOperation extends SyncOperation {
index 4b5343b..e80b42f 100644 (file)
@@ -1,5 +1,8 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2014 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
+ *   Copyright (C) 2015 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,
@@ -56,8 +59,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
  *  properties, and updates the local database with them.
  *  
  *  Does NOT enter in the child folders to synchronize their contents also.
- * 
- *  @author David A. Velasco
  */
 public class SynchronizeFolderOperation extends SyncOperation {
 
@@ -440,7 +441,8 @@ public class SynchronizeFolderOperation extends SyncOperation {
      */
     private void startContentSynchronizations(List<SyncOperation> filesToSyncContents, OwnCloudClient client) 
             throws OperationCancelledException {
-        
+
+        Log_OC.v(TAG, "Starting content synchronization... ");
         RemoteOperationResult contentsResult = null;
         for (SyncOperation op: filesToSyncContents) {
             if (mCancellationRequested.get()) {
index c08c8e5..79370b7 100644 (file)
@@ -1,5 +1,8 @@
-/* ownCloud Android client application
- *   Copyright (C) 2014 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   @author masensio
+ *   Copyright (C) 2015 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,
@@ -35,8 +38,6 @@ import com.owncloud.android.operations.common.SyncOperation;
 /**
  * Unshare file/folder
  * Save the data in Database
- * 
- * @author masensio
  */
 public class UnshareLinkOperation extends SyncOperation {
 
index ac73d96..d2bf5f3 100644 (file)
@@ -1,5 +1,8 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2013 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
+ *   Copyright (C) 2015 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,
@@ -38,8 +41,6 @@ import android.content.Context;
 
 /**
  * Remote operation that checks the version of an ownCloud server and stores it locally
- * 
- * @author David A. Velasco
  */
 public class UpdateOCVersionOperation extends RemoteOperation {
 
index 1536a60..cd5f8a1 100644 (file)
@@ -1,5 +1,8 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2013 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
+ *   Copyright (C) 2015 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,
@@ -26,6 +29,7 @@ import java.io.OutputStream;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Set;
+import java.util.concurrent.CancellationException;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.apache.commons.httpclient.methods.PutMethod;
@@ -55,8 +59,6 @@ import com.owncloud.android.utils.UriUtils;
 
 /**
  * Remote operation performing the upload of a file to an ownCloud server
- * 
- * @author David A. Velasco
  */
 public class UploadFileOperation extends RemoteOperation {
 
@@ -76,7 +78,7 @@ public class UploadFileOperation extends RemoteOperation {
     private String mOriginalStoragePath = null;
     PutMethod mPutMethod = null;
     private Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<OnDatatransferProgressListener>();
-    private final AtomicBoolean mCancellationRequested = new AtomicBoolean(false);
+    private AtomicBoolean mCancellationRequested = new AtomicBoolean(false);
     private Context mContext;
     
     private UploadRemoteFileOperation mUploadOperation;
@@ -212,7 +214,8 @@ public class UploadFileOperation extends RemoteOperation {
 
             // check location of local file; if not the expected, copy to a
             // temporal file before upload (if COPY is the expected behaviour)
-            if (!mOriginalStoragePath.equals(expectedPath) && mLocalBehaviour == FileUploader.LOCAL_BEHAVIOUR_COPY) {
+            if (!mOriginalStoragePath.equals(expectedPath) &&
+                    mLocalBehaviour == FileUploader.LOCAL_BEHAVIOUR_COPY) {
 
                 if (FileStorageUtils.getUsableSpace(mAccount.name) < originalFile.length()) {
                     result = new RemoteOperationResult(ResultCode.LOCAL_STORAGE_FULL);
@@ -221,7 +224,8 @@ public class UploadFileOperation extends RemoteOperation {
 
                 } else {
 
-                    String temporalPath = FileStorageUtils.getTemporalPath(mAccount.name) + mFile.getRemotePath();
+                    String temporalPath = FileStorageUtils.getTemporalPath(mAccount.name) +
+                            mFile.getRemotePath();
                     mFile.setStoragePath(temporalPath);
                     temporalFile = new File(temporalPath);
 
@@ -251,10 +255,10 @@ public class UploadFileOperation extends RemoteOperation {
                             int nRead;
                             byte[] data = new byte[16384];
 
-                            while ((nRead = in.read(data, 0, data.length)) != -1) {
+                            while (!mCancellationRequested.get() &&
+                                    (nRead = in.read(data, 0, data.length)) != -1) {
                                 out.write(data, 0, nRead);
                             }
-
                             out.flush();
 
                         } else {
@@ -268,12 +272,17 @@ public class UploadFileOperation extends RemoteOperation {
                                 out = new FileOutputStream(temporalFile);
                                 byte[] buf = new byte[1024];
                                 int len;
-                                while ((len = in.read(buf)) > 0) {
+                                while (!mCancellationRequested.get() && (len = in.read(buf)) > 0) {
                                     out.write(buf, 0, len);
                                 }
                             }
                         }
 
+                        if (mCancellationRequested.get()) {
+                            result = new RemoteOperationResult(new OperationCancelledException());
+                        }
+
+
                     } catch (Exception e) {
                         result = new RemoteOperationResult(ResultCode.LOCAL_STORAGE_NOT_COPIED);
                         return result;
@@ -283,63 +292,69 @@ public class UploadFileOperation extends RemoteOperation {
                             if (in != null)
                                 in.close();
                         } catch (Exception e) {
-                            Log_OC.d(TAG, "Weird exception while closing input stream for " + mOriginalStoragePath + " (ignoring)", e);
+                            Log_OC.d(TAG, "Weird exception while closing input stream for " +
+                                    mOriginalStoragePath + " (ignoring)", e);
                         }
                         try {
                             if (out != null)
                                 out.close();
                         } catch (Exception e) {
-                            Log_OC.d(TAG, "Weird exception while closing output stream for " + expectedPath + " (ignoring)", e);
+                            Log_OC.d(TAG, "Weird exception while closing output stream for " +
+                                    expectedPath + " (ignoring)", e);
                         }
                     }
                 }
             }
-            localCopyPassed = true;
+            localCopyPassed = (result == null);
 
             /// perform the upload
-            if ( mChunked && (new File(mFile.getStoragePath())).length() > ChunkedUploadRemoteFileOperation.CHUNK_SIZE ) {
-                mUploadOperation = new ChunkedUploadRemoteFileOperation(mFile.getStoragePath(), mFile.getRemotePath(), 
-                        mFile.getMimetype());
+            if ( mChunked &&
+                    (new File(mFile.getStoragePath())).length() >
+                            ChunkedUploadRemoteFileOperation.CHUNK_SIZE ) {
+                mUploadOperation = new ChunkedUploadRemoteFileOperation(mFile.getStoragePath(),
+                        mFile.getRemotePath(), mFile.getMimetype());
             } else {
-                mUploadOperation = new UploadRemoteFileOperation(mFile.getStoragePath(), mFile.getRemotePath(), 
-                        mFile.getMimetype());
+                mUploadOperation = new UploadRemoteFileOperation(mFile.getStoragePath(),
+                        mFile.getRemotePath(), mFile.getMimetype());
             }
             Iterator <OnDatatransferProgressListener> listener = mDataTransferListeners.iterator();
             while (listener.hasNext()) {
                 mUploadOperation.addDatatransferProgressListener(listener.next());
             }
-            result = mUploadOperation.execute(client);
-
-            /// move local temporal file or original file to its corresponding
-            // location in the ownCloud local folder
-            if (result.isSuccess()) {
-                if (mLocalBehaviour == FileUploader.LOCAL_BEHAVIOUR_FORGET) {
-                    mFile.setStoragePath(null);
-
-                } else {
-                    mFile.setStoragePath(expectedPath);
-                    File fileToMove = null;
-                    if (temporalFile != null) { // FileUploader.LOCAL_BEHAVIOUR_COPY
-                                                // ; see where temporalFile was
-                                                // set
-                        fileToMove = temporalFile;
-                    } else { // FileUploader.LOCAL_BEHAVIOUR_MOVE
-                        fileToMove = originalFile;
-                    }
-                    if (!expectedFile.equals(fileToMove)) {
-                        File expectedFolder = expectedFile.getParentFile();
-                        expectedFolder.mkdirs();
-                        if (!expectedFolder.isDirectory() || !fileToMove.renameTo(expectedFile)) {
-                            mFile.setStoragePath(null); // forget the local file
-                            // by now, treat this as a success; the file was
-                            // uploaded; the user won't like that the local file
-                            // is not linked, but this should be a very rare
-                            // fail;
-                            // the best option could be show a warning message
-                            // (but not a fail)
-                            // result = new
-                            // RemoteOperationResult(ResultCode.LOCAL_STORAGE_NOT_MOVED);
-                            // return result;
+            if (!mCancellationRequested.get()) {
+                result = mUploadOperation.execute(client);
+
+                /// move local temporal file or original file to its corresponding
+                // location in the ownCloud local folder
+                if (result.isSuccess()) {
+                    if (mLocalBehaviour == FileUploader.LOCAL_BEHAVIOUR_FORGET) {
+                        mFile.setStoragePath(null);
+
+                    } else {
+                        mFile.setStoragePath(expectedPath);
+                        File fileToMove = null;
+                        if (temporalFile != null) { // FileUploader.LOCAL_BEHAVIOUR_COPY
+                            // ; see where temporalFile was
+                            // set
+                            fileToMove = temporalFile;
+                        } else { // FileUploader.LOCAL_BEHAVIOUR_MOVE
+                            fileToMove = originalFile;
+                        }
+                        if (!expectedFile.equals(fileToMove)) {
+                            File expectedFolder = expectedFile.getParentFile();
+                            expectedFolder.mkdirs();
+                            if (!expectedFolder.isDirectory() || !fileToMove.renameTo(expectedFile)) {
+                                mFile.setStoragePath(null); // forget the local file
+                                // by now, treat this as a success; the file was
+                                // uploaded; the user won't like that the local file
+                                // is not linked, but this should be a very rare
+                                // fail;
+                                // the best option could be show a warning message
+                                // (but not a fail)
+                                // result = new
+                                // RemoteOperationResult(ResultCode.LOCAL_STORAGE_NOT_MOVED);
+                                // return result;
+                            }
                         }
                     }
                 }
@@ -358,19 +373,23 @@ public class UploadFileOperation extends RemoteOperation {
                 temporalFile.delete();
             }
             if (result.isSuccess()) {
-                Log_OC.i(TAG, "Upload of " + mOriginalStoragePath + " to " + mRemotePath + ": " + result.getLogMessage());
+                Log_OC.i(TAG, "Upload of " + mOriginalStoragePath + " to " + mRemotePath + ": " +
+                        result.getLogMessage());
             } else {
                 if (result.getException() != null) {
                     String complement = "";
                     if (!nameCheckPassed) {
                         complement = " (while checking file existence in server)";
                     } else if (!localCopyPassed) {
-                        complement = " (while copying local file to " + FileStorageUtils.getSavePath(mAccount.name)
+                        complement = " (while copying local file to " +
+                                FileStorageUtils.getSavePath(mAccount.name)
                                 + ")";
                     }
-                    Log_OC.e(TAG, "Upload of " + mOriginalStoragePath + " to " + mRemotePath + ": " + result.getLogMessage() + complement, result.getException());
+                    Log_OC.e(TAG, "Upload of " + mOriginalStoragePath + " to " + mRemotePath +
+                            ": " + result.getLogMessage() + complement, result.getException());
                 } else {
-                    Log_OC.e(TAG, "Upload of " + mOriginalStoragePath + " to " + mRemotePath + ": " + result.getLogMessage());
+                    Log_OC.e(TAG, "Upload of " + mOriginalStoragePath + " to " + mRemotePath +
+                            ": " + result.getLogMessage());
                 }
             }
         }
@@ -385,7 +404,8 @@ public class UploadFileOperation extends RemoteOperation {
         newFile.setFileLength(mFile.getFileLength());
         newFile.setMimetype(mFile.getMimetype());
         newFile.setModificationTimestamp(mFile.getModificationTimestamp());
-        newFile.setModificationTimestampAtLastSyncForData(mFile.getModificationTimestampAtLastSyncForData());
+        newFile.setModificationTimestampAtLastSyncForData(
+                mFile.getModificationTimestampAtLastSyncForData());
         // newFile.setEtag(mFile.getEtag())
         newFile.setKeepInSync(mFile.keepInSync());
         newFile.setLastSyncDateForProperties(mFile.getLastSyncDateForProperties());
@@ -400,7 +420,8 @@ public class UploadFileOperation extends RemoteOperation {
      * Checks if remotePath does not exist in the server and returns it, or adds
      * a suffix to it in order to avoid the server file is overwritten.
      * 
-     * @param string
+     * @param wc
+     * @param remotePath
      * @return
      */
     private String getAvailableRemotePath(OwnCloudClient wc, String remotePath) throws Exception {
@@ -436,12 +457,16 @@ public class UploadFileOperation extends RemoteOperation {
     }
 
     private boolean existsFile(OwnCloudClient client, String remotePath){
-        ExistenceCheckRemoteOperation existsOperation = new ExistenceCheckRemoteOperation(remotePath, mContext, false);
+        ExistenceCheckRemoteOperation existsOperation =
+                new ExistenceCheckRemoteOperation(remotePath, mContext, false);
         RemoteOperationResult result = existsOperation.execute(client);
         return result.isSuccess();
     }
     
     public void cancel() {
-        mUploadOperation.cancel();
+        mCancellationRequested = new AtomicBoolean(true);
+        if (mUploadOperation != null) {
+            mUploadOperation.cancel();
+        }
     }
 }
index 8c5678b..512be4e 100644 (file)
@@ -1,5 +1,8 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2014 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
+ *   Copyright (C) 2015 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,
@@ -32,8 +35,6 @@ import android.os.Handler;
  * with local data in the device.
  * 
  * Provides methods to execute the operation both synchronously or asynchronously.
- * 
- * @author David A. Velasco 
  */
 public abstract class SyncOperation extends RemoteOperation {
        
index 4ea4812..737c664 100644 (file)
@@ -1,6 +1,10 @@
-/* ownCloud Android client application
+/**
+ *   ownCloud Android client application
+ *
+ *   @author Bartek Przybylski
+ *   @author David A. Velasco
  *   Copyright (C) 2011  Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
+ *   Copyright (C) 2015 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,
@@ -45,10 +49,6 @@ import android.text.TextUtils;
 
 /**
  * The ContentProvider for the ownCloud App.
- * 
- * @author Bartek Przybylski
- * @author David A. Velasco
- * 
  */
 public class FileContentProvider extends ContentProvider {
 
index 2e57ada..6a32af0 100644 (file)
@@ -1,5 +1,7 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2014 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   Copyright (C) 2015 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,
@@ -37,7 +39,6 @@ import com.owncloud.android.lib.common.operations.OnRemoteOperationListener;
 import com.owncloud.android.lib.common.operations.RemoteOperation;
 import com.owncloud.android.lib.common.operations.RemoteOperationResult;
 import com.owncloud.android.lib.common.utils.Log_OC;
-import com.owncloud.android.lib.resources.files.ExistenceCheckRemoteOperation;
 import com.owncloud.android.lib.resources.shares.ShareType;
 import com.owncloud.android.lib.resources.users.GetRemoteUserNameOperation;
 import com.owncloud.android.operations.common.SyncOperation;
@@ -84,26 +85,20 @@ public class OperationsService extends Service {
     public static final String EXTRA_RESULT = "RESULT";
     public static final String EXTRA_NEW_PARENT_PATH = "NEW_PARENT_PATH";
     public static final String EXTRA_FILE = "FILE";
+    public static final String EXTRA_PASSWORD_SHARE = "PASSWORD_SHARE";
 
-    // TODO review if ALL OF THEM are necessary
-    public static final String EXTRA_SUCCESS_IF_ABSENT = "SUCCESS_IF_ABSENT";
-    public static final String EXTRA_USERNAME = "USERNAME";
-    public static final String EXTRA_PASSWORD = "PASSWORD";
-    public static final String EXTRA_AUTH_TOKEN = "AUTH_TOKEN";
     public static final String EXTRA_COOKIE = "COOKIE";
     
     public static final String ACTION_CREATE_SHARE = "CREATE_SHARE";
     public static final String ACTION_UNSHARE = "UNSHARE";
     public static final String ACTION_GET_SERVER_INFO = "GET_SERVER_INFO";
     public static final String ACTION_OAUTH2_GET_ACCESS_TOKEN = "OAUTH2_GET_ACCESS_TOKEN";
-    public static final String ACTION_EXISTENCE_CHECK = "EXISTENCE_CHECK";
     public static final String ACTION_GET_USER_NAME = "GET_USER_NAME";
     public static final String ACTION_RENAME = "RENAME";
     public static final String ACTION_REMOVE = "REMOVE";
     public static final String ACTION_CREATE_FOLDER = "CREATE_FOLDER";
     public static final String ACTION_SYNC_FILE = "SYNC_FILE";
     public static final String ACTION_SYNC_FOLDER = "SYNC_FOLDER";  // for the moment, just to download
-    //public static final String ACTION_CANCEL_SYNC_FOLDER = "CANCEL_SYNC_FOLDER";  // for the moment, just to download
     public static final String ACTION_MOVE_FILE = "MOVE_FILE";
     
     public static final String ACTION_OPERATION_ADDED = OperationsService.class.getName() + ".OPERATION_ADDED";
@@ -117,18 +112,11 @@ public class OperationsService extends Service {
     private static class Target {
         public Uri mServerUrl = null;
         public Account mAccount = null;
-        public String mUsername = null;
-        public String mPassword = null;
-        public String mAuthToken = null;
         public String mCookie = null;
         
-        public Target(Account account, Uri serverUrl, String username, String password, String authToken,
-                String cookie) {
+        public Target(Account account, Uri serverUrl, String cookie) {
             mAccount = account;
             mServerUrl = serverUrl;
-            mUsername = username;
-            mPassword = password;
-            mAuthToken = authToken;
             mCookie = cookie;
         }
     }
@@ -144,6 +132,8 @@ public class OperationsService extends Service {
     @Override
     public void onCreate() {
         super.onCreate();
+        Log_OC.d(TAG, "Creating service");
+
         /// First worker thread for most of operations 
         HandlerThread thread = new HandlerThread("Operations thread", Process.THREAD_PRIORITY_BACKGROUND);
         thread.start();
@@ -165,12 +155,12 @@ public class OperationsService extends Service {
      */
     @Override
     public int onStartCommand(Intent intent, int flags, int startId) {
-        // WIP: for the moment, only SYNC_FOLDER and CANCEL_SYNC_FOLDER is expected here;
+        Log_OC.d(TAG, "Starting command with id " + startId);
+
+        // WIP: for the moment, only SYNC_FOLDER is expected here;
         // the rest of the operations are requested through the Binder
         if (ACTION_SYNC_FOLDER.equals(intent.getAction())) {
 
-            /*Log_OC.v("NOW " + TAG + ", thread " + Thread.currentThread().getName(), "Received request to sync folder");*/
-
             if (!intent.hasExtra(EXTRA_ACCOUNT) || !intent.hasExtra(EXTRA_REMOTE_PATH)) {
                 Log_OC.e(TAG, "Not enough information provided in intent");
                 return START_NOT_STICKY;
@@ -186,10 +176,6 @@ public class OperationsService extends Service {
                 Message msg = mSyncFolderHandler.obtainMessage();
                 msg.arg1 = startId;
                 msg.obj = itemSyncKey;
-                /*Log_OC.v(
-                        "NOW " + TAG + ", thread " + Thread.currentThread().getName(),
-                        "Sync folder " + remotePath + " added to queue"
-                );*/
                 mSyncFolderHandler.sendMessage(msg);
             }
 
@@ -204,7 +190,7 @@ public class OperationsService extends Service {
 
     @Override
     public void onDestroy() {
-        //Log_OC.wtf(TAG, "onDestroy init" );
+        Log_OC.v(TAG, "Destroying service" );
         // Saving cookies
         try {
             OwnCloudClientManagerFactory.getDefaultSingleton().
@@ -221,10 +207,16 @@ public class OperationsService extends Service {
             e.printStackTrace();
         }
         
-        //Log_OC.wtf(TAG, "Clear mUndispatchedFinishedOperations" );
         mUndispatchedFinishedOperations.clear();
-        
-        //Log_OC.wtf(TAG, "onDestroy end" );
+
+        mOperationsBinder = null;
+
+        mOperationsHandler.getLooper().quit();
+        mOperationsHandler = null;
+
+        mSyncFolderHandler.getLooper().quit();
+        mSyncFolderHandler = null;
+
         super.onDestroy();
     }
 
@@ -244,7 +236,7 @@ public class OperationsService extends Service {
      */
     @Override
     public boolean onUnbind(Intent intent) {
-        ((OperationsServiceBinder)mOperationsBinder).clearListeners();
+        mOperationsBinder.clearListeners();
         return false;   // not accepting rebinding (default behaviour)
     }
 
@@ -276,10 +268,6 @@ public class OperationsService extends Service {
          * @param file          A folder in the queue of pending synchronizations
          */
         public void cancel(Account account, OCFile file) {
-            /*Log_OC.v(
-                    "NOW " + TAG + ", thread " + Thread.currentThread().getName(),
-                    "Received request to cancel folder " + file.getRemotePath()
-            );*/
             mSyncFolderHandler.cancel(account, file);
         }
 
@@ -413,6 +401,7 @@ public class OperationsService extends Service {
         @Override
         public void handleMessage(Message msg) {
             nextOperation();
+            Log_OC.d(TAG, "Stopping after command with id " + msg.arg1);
             mService.stopSelf(msg.arg1);
         }
         
@@ -447,19 +436,10 @@ public class OperationsService extends Service {
                             );
                         } else {
                             OwnCloudCredentials credentials = null;
-                            if (mLastTarget.mUsername != null && 
-                                    mLastTarget.mUsername.length() > 0) {
-                                credentials = OwnCloudCredentialsFactory.newBasicCredentials(
-                                        mLastTarget.mUsername, 
-                                        mLastTarget.mPassword);  // basic
-                                
-                            } else if (mLastTarget.mAuthToken != null && 
-                                    mLastTarget.mAuthToken.length() > 0) {
-                                credentials = OwnCloudCredentialsFactory.newBearerCredentials(
-                                        mLastTarget.mAuthToken);  // bearer token
-                                
-                            } else if (mLastTarget.mCookie != null &&
+                            if (mLastTarget.mCookie != null &&
                                     mLastTarget.mCookie.length() > 0) {
+                                // just used for GetUserName
+                                // TODO refactor to run GetUserName as AsyncTask in the context of AuthenticatorActivity
                                 credentials = OwnCloudCredentialsFactory.newSamlSsoCredentials(
                                         mLastTarget.mCookie); // SAML SSO
                             }
@@ -508,7 +488,7 @@ public class OperationsService extends Service {
                 }
                 
                 //sendBroadcastOperationFinished(mLastTarget, mCurrentOperation, result);
-                mService.dispatchResultToOperationListeners(mLastTarget, mCurrentOperation, result);
+                mService.dispatchResultToOperationListeners(mCurrentOperation, result);
             }
         }
 
@@ -536,26 +516,22 @@ public class OperationsService extends Service {
             } else {
                 Account account = operationIntent.getParcelableExtra(EXTRA_ACCOUNT);
                 String serverUrl = operationIntent.getStringExtra(EXTRA_SERVER_URL);
-                String username = operationIntent.getStringExtra(EXTRA_USERNAME);
-                String password = operationIntent.getStringExtra(EXTRA_PASSWORD);
-                String authToken = operationIntent.getStringExtra(EXTRA_AUTH_TOKEN);
                 String cookie = operationIntent.getStringExtra(EXTRA_COOKIE);
                 target = new Target(
                         account, 
                         (serverUrl == null) ? null : Uri.parse(serverUrl),
-                        username,
-                        password,
-                        authToken,
                         cookie
                 );
                 
                 String action = operationIntent.getAction();
                 if (action.equals(ACTION_CREATE_SHARE)) {  // Create Share
                     String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);
+                    String password = operationIntent.getStringExtra(EXTRA_PASSWORD_SHARE);
                     Intent sendIntent = operationIntent.getParcelableExtra(EXTRA_SEND_INTENT);
                     if (remotePath.length() > 0) {
-                        operation = new CreateShareOperation(OperationsService.this, remotePath, ShareType.PUBLIC_LINK,
-                                "", false, "", 1, sendIntent);
+                        operation = new CreateShareOperation(OperationsService.this, remotePath,
+                                ShareType.PUBLIC_LINK,
+                                "", false, password, 1, sendIntent);
                     }
                     
                 } else if (action.equals(ACTION_UNSHARE)) {  // Unshare file
@@ -580,12 +556,6 @@ public class OperationsService extends Service {
                             getString(R.string.oauth2_grant_type),
                             oauth2QueryParameters);
                     
-                } else if (action.equals(ACTION_EXISTENCE_CHECK)) {
-                    // Existence Check 
-                    String remotePath = operationIntent.getStringExtra(EXTRA_REMOTE_PATH);
-                    boolean successIfAbsent = operationIntent.getBooleanExtra(EXTRA_SUCCESS_IF_ABSENT, false);
-                    operation = new ExistenceCheckRemoteOperation(remotePath, OperationsService.this, successIfAbsent);
-                    
                 } else if (action.equals(ACTION_GET_USER_NAME)) {
                     // Get User Name
                     operation = new GetRemoteUserNameOperation();
@@ -697,12 +667,12 @@ public class OperationsService extends Service {
     /**
      * Notifies the currently subscribed listeners about the end of an operation.
      *
-     * @param target            Account or URL pointing to an OC server.
      * @param operation         Finished operation.
      * @param result            Result of the operation.
      */
     protected void dispatchResultToOperationListeners(
-            Target target, final RemoteOperation operation, final RemoteOperationResult result) {
+            final RemoteOperation operation, final RemoteOperationResult result
+    ) {
         int count = 0;
         Iterator<OnRemoteOperationListener> listeners = mOperationsBinder.mBoundListeners.keySet().iterator();
         while (listeners.hasNext()) {
index b68d930..57271eb 100644 (file)
@@ -1,4 +1,6 @@
-/* ownCloud Android client application
+/**
+ *   ownCloud Android client application
+ *
  *   Copyright (C) 2015 ownCloud Inc.
  *
  *   This program is free software: you can redistribute it and/or modify
@@ -86,9 +88,8 @@ class SyncFolderHandler extends Handler {
     @Override
     public void handleMessage(Message msg) {
         Pair<Account, String> itemSyncKey = (Pair<Account, String>) msg.obj;
-        /*Log_OC.v(   "NOW " + TAG + ", thread " + Thread.currentThread().getName(),
-                    "Handling sync folder " + itemSyncKey.second);*/
         doOperation(itemSyncKey.first, itemSyncKey.second);
+        Log_OC.d(TAG, "Stopping after command with id " + msg.arg1);
         mService.stopSelf(msg.arg1);
     }
 
@@ -98,8 +99,6 @@ class SyncFolderHandler extends Handler {
      */
     private void doOperation(Account account, String remotePath) {
 
-        /*Log_OC.v(   "NOW " + TAG + ", thread " + Thread.currentThread().getName(),
-                "Getting sync folder " + remotePath);*/
         mCurrentSyncOperation = mPendingOperations.get(account, remotePath);
 
         if (mCurrentSyncOperation != null) {
@@ -120,8 +119,6 @@ class SyncFolderHandler extends Handler {
                 mOwnCloudClient = OwnCloudClientManagerFactory.getDefaultSingleton().
                         getClientFor(ocAccount, mService);
 
-                /*Log_OC.v(   "NOW " + TAG + ", thread " + Thread.currentThread().getName(),
-                        "Executing sync folder " + remotePath);*/
                 result = mCurrentSyncOperation.execute(mOwnCloudClient, mStorageManager);
 
             } catch (AccountsException e) {
@@ -129,12 +126,9 @@ class SyncFolderHandler extends Handler {
             } catch (IOException e) {
                 Log_OC.e(TAG, "Error while trying to get authorization", e);
             } finally {
-                /*Log_OC.v(   "NOW " + TAG + ", thread " + Thread.currentThread().getName(),
-                        "Removing payload " + remotePath);*/
-
                 mPendingOperations.removePayload(account, remotePath);
 
-                mService.dispatchResultToOperationListeners(null, mCurrentSyncOperation, result);
+                mService.dispatchResultToOperationListeners(mCurrentSyncOperation, result);
 
                 sendBroadcastFinishedSyncFolder(account, remotePath, result.isSuccess());
             }
@@ -158,26 +152,17 @@ class SyncFolderHandler extends Handler {
             Log_OC.e(TAG, "Cannot cancel with NULL parameters");
             return;
         }
-        /*Log_OC.v(   "NOW " + TAG + ", thread " + Thread.currentThread().getName(),
-                "Removing sync folder " + file.getRemotePath());*/
         Pair<SynchronizeFolderOperation, String> removeResult =
                 mPendingOperations.remove(account, file.getRemotePath());
         SynchronizeFolderOperation synchronization = removeResult.first;
         if (synchronization != null) {
-            /*Log_OC.v(   "NOW " + TAG + ", thread " + Thread.currentThread().getName(),
-                    "Canceling returned sync of " + file.getRemotePath());*/
             synchronization.cancel();
         } else {
             // TODO synchronize?
             if (mCurrentSyncOperation != null && mCurrentAccount != null &&
                     mCurrentSyncOperation.getRemotePath().startsWith(file.getRemotePath()) &&
                     account.name.equals(mCurrentAccount.name)) {
-                /*Log_OC.v(   "NOW " + TAG + ", thread " + Thread.currentThread().getName(),
-                        "Canceling current sync as descendant: " + mCurrentSyncOperation.getRemotePath());*/
                 mCurrentSyncOperation.cancel();
-            } else {
-                /*Log_OC.v(   "NOW " + TAG + ", thread " + Thread.currentThread().getName(),
-                        "Nothing else in cancelation of " + file.getRemotePath());*/
             }
         }
 
index 114f0e4..83de450 100644 (file)
@@ -1,6 +1,9 @@
-/* ownCloud Android client application
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
  *   Copyright (C) 2012 Bartek Przybylski
- *   Copyright (C) 2012-2014 ownCloud Inc.
+ *   Copyright (C) 2015 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,
@@ -54,8 +57,6 @@ import com.owncloud.android.utils.FileStorageUtils;
  * memory. To minimize the impact of this, the service always returns
  * Service.START_STICKY, and the later restart of the service is explicitly
  * considered in {@link FileObserverService#onStartCommand(Intent, int, int)}.
- * 
- * @author David A. Velasco
  */
 public class FileObserverService extends Service {
 
index 67b41a1..5329b52 100644 (file)
@@ -1,5 +1,8 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2014 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
+ *   Copyright (C) 2015 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,
@@ -46,8 +49,6 @@ import com.owncloud.android.ui.activity.ConflictsResolveActivity;
  *  The second case requires to monitor the folder parent of the files, since a direct 
  *  {@link FileObserver} on it will not receive more events after the file is deleted to
  *  be replaced.
- * 
- * @author David A. Velasco
  */
 public class FolderObserver extends FileObserver {
 
index 28cfa54..7ccbc11 100644 (file)
@@ -1,6 +1,10 @@
-/* ownCloud Android client application\r
+/**\r
+ *   ownCloud Android client application\r
+ *\r
+ *   @author sassman\r
+ *   @author David A. Velasco\r
  *   Copyright (C) 2011  Bartek Przybylski\r
- *   Copyright (C) 2012-2013 ownCloud Inc.\r
+ *   Copyright (C) 2015 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
@@ -44,9 +48,6 @@ import android.content.Context;
  * resource types, like FileSync, ConcatsSync, CalendarSync, etc..\r
  * \r
  * Implements the standard {@link AbstractThreadedSyncAdapter}.\r
- * \r
- * @author sassman\r
- * @author David A. Velasco\r
  */\r
 public abstract class AbstractOwnCloudSyncAdapter extends\r
         AbstractThreadedSyncAdapter {\r
index 3ba1676..d3ab06c 100644 (file)
@@ -1,6 +1,8 @@
-/* ownCloud Android client application
+/**
+ *   ownCloud Android client application
+ *
  *   Copyright (C) 2012 Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
+ *   Copyright (C) 2015 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,
index 6d7c46c..d907bb4 100644 (file)
@@ -1,6 +1,8 @@
-/* ownCloud Android client application
+/**
+ *   ownCloud Android client application
+ *
  *   Copyright (C) 2012 Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
+ *   Copyright (C) 2015 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,
index 4683896..07e68c6 100644 (file)
@@ -1,6 +1,10 @@
-/* ownCloud Android client application
+/**
+ *   ownCloud Android client application
+ *
+ *   @author Bartek Przybylski
+ *   @author David A. Velasco
  *   Copyright (C) 2011  Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
+ *   Copyright (C) 2015 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,
@@ -55,9 +59,6 @@ import android.support.v4.app.NotificationCompat;
  * ownCloud files.
  * 
  * Performs a full synchronization of the account recieved in {@link #onPerformSync(Account, Bundle, String, ContentProviderClient, SyncResult)}.
- * 
- * @author Bartek Przybylski
- * @author David A. Velasco
  */
 public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter {
 
index 5da8c24..e48f91f 100644 (file)
@@ -1,6 +1,10 @@
-/* ownCloud Android client application\r
+/**\r
+ *   ownCloud Android client application\r
+ *\r
+ *   @author Bartek Przybylski\r
+ *   @author David A. Velasco\r
  *   Copyright (C) 2011  Bartek Przybylski\r
- *   Copyright (C) 2012-2013 ownCloud Inc.\r
+ *   Copyright (C) 2015 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
@@ -24,10 +28,7 @@ import android.os.IBinder;
 /**\r
  * Background service for synchronizing remote files with their local state.\r
  * \r
- * Serves as a connector to an instance of {@link FileSyncAdapter}, as required by standard Android APIs. \r
- * \r
- * @author Bartek Przybylski\r
- * @author David A. Velasco\r
+ * Serves as a connector to an instance of {@link FileSyncAdapter}, as required by standard Android APIs.\r
  */\r
 public class FileSyncService extends Service {\r
     \r
index a65f3ad..e1fa805 100644 (file)
@@ -1,6 +1,9 @@
-/* ownCloud Android client application\r
+/**\r
+ *   ownCloud Android client application\r
+ *\r
+ *   @author Bartek Przybylski\r
  *   Copyright (C) 2011  Bartek Przybylski\r
- *   Copyright (C) 2012-2013 ownCloud Inc.\r
+ *   Copyright (C) 2015 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
@@ -22,9 +25,6 @@ import android.view.View.OnClickListener;
 \r
 /**\r
  * Represents an Item on the ActionBar.\r
- * \r
- * @author Bartek Przybylski\r
- * \r
  */\r
 public class ActionItem {\r
     private Drawable mIcon;\r
index dac083a..b451fca 100644 (file)
@@ -1,4 +1,6 @@
-/* ownCloud Android client application
+/**
+ *   ownCloud Android client application
+ *
  *   Copyright (C) 2014 ownCloud Inc.
  *
  *   This program is free software: you can redistribute it and/or modify
index fccf56d..44f8976 100644 (file)
@@ -1,6 +1,9 @@
-/* ownCloud Android client application\r
+/**\r
+ *   ownCloud Android client application\r
+ *\r
+ *   @author Lorensius. W. T\r
  *   Copyright (C) 2011  Bartek Przybylski\r
- *   Copyright (C) 2012-2013 ownCloud Inc.\r
+ *   Copyright (C) 2015 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
@@ -32,9 +35,6 @@ import android.widget.PopupWindow;
 \r
 /**\r
  * Represents a custom PopupWindows\r
- * \r
- * @author Lorensius. W. T\r
- * \r
  */\r
 public class CustomPopup {\r
     protected final View mAnchor;\r
index 9fe885b..2258764 100644 (file)
@@ -1,6 +1,9 @@
-/* ownCloud Android client application
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
  *   Copyright (C) 2012 Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
+ *   Copyright (C) 2012-2015 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,
@@ -23,16 +26,18 @@ import android.graphics.Canvas;
 import android.util.AttributeSet;
 import android.widget.ListView;
 
+import com.owncloud.android.lib.common.utils.Log_OC;
+
 /**
  * ListView allowing to specify the position of an item that should be centered in the visible area, if possible.
- * 
- * The cleanest way I found to overcome the problem due to getHeight() returns 0 until the view is really drawn. 
- *  
- * @author David A. Velasco
+ *
+ * The cleanest way I found to overcome the problem due to getHeight() returns 0 until the view is really drawn.
  */
 public class ExtendedListView extends ListView {
 
-    private int mPositionToSetAndCenter;
+    private static final String TAG = ExtendedListView.class.getSimpleName();
+
+    private int mPositionToSetAndCenter = 0;
 
     public ExtendedListView(Context context) {
         super(context);
@@ -48,26 +53,28 @@ public class ExtendedListView extends ListView {
 
     /**
      * {@inheritDoc}
-     * 
-     * 
+     *
+     *
      */
     @Override
     protected void onDraw (Canvas canvas) {
         super.onDraw(canvas);
         if (mPositionToSetAndCenter > 0) {
+            Log_OC.v(TAG, "Centering around position " + mPositionToSetAndCenter);
             this.setSelectionFromTop(mPositionToSetAndCenter, getHeight() / 2);
             mPositionToSetAndCenter = 0;
         }
     }
-    
+
     /**
      * Public method to set the position of the item that should be centered in the visible area of the view.
-     * 
+     *
      * The position is saved here and checked in onDraw().
-     *  
+     *
      * @param position         Position (in the list of items) of the item to center in the visible area.     
      */
     public void setAndCenterSelection(int position) {
         mPositionToSetAndCenter = position;
     }
-}
+
+}
\ No newline at end of file
index e38d29a..946a41e 100644 (file)
@@ -1,4 +1,6 @@
-/* ownCloud Android client application
+/**
+ *   ownCloud Android client application
+ *
  *   Copyright (C) 2014 ownCloud Inc.
  *
  *   This program is free software: you can redistribute it and/or modify
index 86fe3fe..db27951 100644 (file)
@@ -1,6 +1,9 @@
-/* ownCloud Android client application\r
+/**\r
+ *   ownCloud Android client application\r
+ *\r
+ *   @author Lorensius. W. T\r
  *   Copyright (C) 2011  Bartek Przybylski\r
- *   Copyright (C) 2012-2013 ownCloud Inc.\r
+ *   Copyright (C) 2015 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
@@ -42,8 +45,6 @@ import com.owncloud.android.R;
 /**\r
  * Popup window, shows action list as icon and text like the one in Gallery3D\r
  * app.\r
- * \r
- * @author Lorensius. W. T\r
  */\r
 public class QuickAction extends CustomPopup {\r
     private final View root;\r
index 8f562b3..4437cce 100644 (file)
@@ -1,3 +1,22 @@
+/**
+ *   ownCloud Android client application
+ *
+ *   Copyright (C) 2015 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;
 
 import android.content.Context;
diff --git a/src/com/owncloud/android/ui/SquareImageView.java b/src/com/owncloud/android/ui/SquareImageView.java
new file mode 100644 (file)
index 0000000..b1613fd
--- /dev/null
@@ -0,0 +1,44 @@
+/**
+ *   ownCloud Android client application
+ *
+ *   Copyright (C) 2015 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;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+
+public class SquareImageView extends ImageView {
+
+    public SquareImageView(Context context) {
+        super(context);
+    }
+
+    public SquareImageView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public SquareImageView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        super.onMeasure(widthMeasureSpec, widthMeasureSpec);
+    }
+}
diff --git a/src/com/owncloud/android/ui/SquareLinearLayout.java b/src/com/owncloud/android/ui/SquareLinearLayout.java
new file mode 100644 (file)
index 0000000..c65c51f
--- /dev/null
@@ -0,0 +1,44 @@
+/**
+ *   ownCloud Android client application
+ *
+ *   Copyright (C) 2015 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;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.LinearLayout;
+
+public class SquareLinearLayout extends LinearLayout {
+
+    public SquareLinearLayout(Context context) {
+        super(context);
+    }
+
+    public SquareLinearLayout(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public SquareLinearLayout(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        super.onMeasure(widthMeasureSpec, widthMeasureSpec);
+    }
+}
index 2916ac3..043f67e 100644 (file)
@@ -1,6 +1,8 @@
-/* ownCloud Android client application
+/**
+ *   ownCloud Android client application
+ *
  *   Copyright (C) 2012 Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
+ *   Copyright (C) 2015 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,
index 509e5c7..c3db9a4 100644 (file)
@@ -1,6 +1,10 @@
-/* ownCloud Android client application
+/**
+ *   ownCloud Android client application
+ *
+ *   @author Bartek Przybylski
+ *   @author David A. Velasco
  *   Copyright (C) 2012 Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
+ *   Copyright (C) 2015 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,
@@ -32,10 +36,7 @@ import android.os.Bundle;
 
 /**
  * Wrapper activity which will be launched if keep-in-sync file will be modified by external
- * application. 
- * 
- * @author Bartek Przybylski
- * @author David A. Velasco
+ * application.
  */
 public class ConflictsResolveActivity extends FileActivity implements OnConflictDecisionMadeListener {
 
index b503c37..de5b3c3 100644 (file)
@@ -1,5 +1,8 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2014 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
+ *   Copyright (C) 2015 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,
@@ -28,8 +31,6 @@ import android.widget.Toast;
 
 /**
  * Activity copying the text of the received Intent into the system clibpoard.
- * 
- * @author David A. Velasco
  */
 @SuppressWarnings("deprecation")
 public class CopyToClipboardActivity extends Activity {
index bffec8b..9405ca7 100644 (file)
@@ -1,5 +1,8 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2013 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
+ *   Copyright (C) 2015 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,
@@ -57,8 +60,6 @@ import com.owncloud.android.utils.FileStorageUtils;
  * files.
  * 
  * Shown when the error notification summarizing the list of errors is clicked by the user.
- * 
- * @author David A. Velasco
  */
 public class ErrorsWhileCopyingHandlerActivity  extends SherlockFragmentActivity implements OnClickListener {
 
@@ -129,9 +130,7 @@ public class ErrorsWhileCopyingHandlerActivity  extends SherlockFragmentActivity
     
     /**
      * Customized adapter, showing the local files as main text in two-lines list item and the remote files
-     * as the secondary text. 
-     * 
-     * @author David A. Velasco
+     * as the secondary text.
      */
     public class ErrorsWhileCopyingListAdapter extends ArrayAdapter<String> {
         
@@ -200,8 +199,6 @@ public class ErrorsWhileCopyingHandlerActivity  extends SherlockFragmentActivity
     
     /**
      * Asynchronous task performing the move of all the local files to the ownCloud folder.
-     * 
-     * @author David A. Velasco
      */
     private class MoveFilesTask extends AsyncTask<Void, Void, Boolean> {
 
index 536800b..7f48b9e 100644 (file)
@@ -1,6 +1,9 @@
-/* ownCloud Android client application
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
  *   Copyright (C) 2011  Bartek Przybylski
- *   Copyright (C) 2012-2014 ownCloud Inc.
+ *   Copyright (C) 2015 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,
@@ -56,30 +59,31 @@ import com.owncloud.android.lib.common.utils.Log_OC;
 import com.owncloud.android.operations.CreateShareOperation;
 import com.owncloud.android.operations.SynchronizeFolderOperation;
 import com.owncloud.android.operations.UnshareLinkOperation;
-
 import com.owncloud.android.services.OperationsService;
 import com.owncloud.android.services.OperationsService.OperationsServiceBinder;
+import com.owncloud.android.ui.dialog.CreateFolderDialogFragment;
 import com.owncloud.android.ui.dialog.LoadingDialog;
+import com.owncloud.android.ui.dialog.SharePasswordDialogFragment;
 import com.owncloud.android.utils.ErrorMessageAdapter;
 
 
 /**
  * Activity with common behaviour for activities handling {@link OCFile}s in ownCloud {@link Account}s .
- * 
- * @author David A. Velasco
  */
-public class FileActivity extends SherlockFragmentActivity 
-implements OnRemoteOperationListener, ComponentsGetter {
+public class FileActivity extends SherlockFragmentActivity
+        implements OnRemoteOperationListener, ComponentsGetter {
 
     public static final String EXTRA_FILE = "com.owncloud.android.ui.activity.FILE";
     public static final String EXTRA_ACCOUNT = "com.owncloud.android.ui.activity.ACCOUNT";
     public static final String EXTRA_WAITING_TO_PREVIEW = "com.owncloud.android.ui.activity.WAITING_TO_PREVIEW";
-    public static final String EXTRA_FROM_NOTIFICATION= "com.owncloud.android.ui.activity.FROM_NOTIFICATION";
+    public static final String EXTRA_FROM_NOTIFICATION = "com.owncloud.android.ui.activity.FROM_NOTIFICATION";
     
     public static final String TAG = FileActivity.class.getSimpleName();
     
     private static final String DIALOG_WAIT_TAG = "DIALOG_WAIT";
-    private static final String KEY_WAITING_FOR_OP_ID = "WAITING_FOR_OP_ID";;
+    private static final String KEY_WAITING_FOR_OP_ID = "WAITING_FOR_OP_ID";
+    private static final String DIALOG_SHARE_PASSWORD = "DIALOG_SHARE_PASSWORD";
+    private static final String KEY_TRY_SHARE_AGAIN = "TRY_SHARE_AGAIN";
     
     protected static final long DELAY_TO_REQUEST_OPERATION_ON_ACTIVITY_RESULTS = 200;
     
@@ -117,6 +121,8 @@ implements OnRemoteOperationListener, ComponentsGetter {
     protected FileDownloaderBinder mDownloaderBinder = null;
     protected FileUploaderBinder mUploaderBinder = null;
     private ServiceConnection mDownloadServiceConnection, mUploadServiceConnection = null;
+
+    private boolean mTryShareAgain = false;
     
     
     /**
@@ -139,6 +145,7 @@ implements OnRemoteOperationListener, ComponentsGetter {
             mFileOperationsHelper.setOpIdWaitingFor(
                     savedInstanceState.getLong(KEY_WAITING_FOR_OP_ID, Long.MAX_VALUE)
                     );
+            mTryShareAgain = savedInstanceState.getBoolean(KEY_TRY_SHARE_AGAIN);
         } else {
             account = getIntent().getParcelableExtra(FileActivity.EXTRA_ACCOUNT);
             mFile = getIntent().getParcelableExtra(FileActivity.EXTRA_FILE);
@@ -158,7 +165,7 @@ implements OnRemoteOperationListener, ComponentsGetter {
         if (mUploadServiceConnection != null) {
             bindService(new Intent(this, FileUploader.class), mUploadServiceConnection, Context.BIND_AUTO_CREATE);
         }
-        
+
     }
 
     
@@ -221,6 +228,7 @@ implements OnRemoteOperationListener, ComponentsGetter {
             unbindService(mUploadServiceConnection);
             mUploadServiceConnection = null;
         }
+
         super.onDestroy();
     }
     
@@ -256,8 +264,6 @@ implements OnRemoteOperationListener, ComponentsGetter {
      *  to create a new ownCloud {@link Account}.
      *  
      *  POSTCONDITION: updates {@link #mAccountWasSet} and {@link #mAccountWasRestored}.
-     *   
-     *  @return     'True' if the checked {@link Account} was valid.
      */
     private void swapToDefaultAccount() {
         // default to the most recently used account
@@ -302,6 +308,7 @@ implements OnRemoteOperationListener, ComponentsGetter {
         outState.putParcelable(FileActivity.EXTRA_ACCOUNT, mAccount);
         outState.putBoolean(FileActivity.EXTRA_FROM_NOTIFICATION, mFromNotification);
         outState.putLong(KEY_WAITING_FOR_OP_ID, mFileOperationsHelper.getOpIdWaitingFor());
+        outState.putBoolean(KEY_TRY_SHARE_AGAIN, mTryShareAgain);
     }
     
     
@@ -347,7 +354,14 @@ implements OnRemoteOperationListener, ComponentsGetter {
     protected boolean isRedirectingToSetupAccount() {
         return mRedirectingToSetupAccount;
     }
-    
+
+    public boolean isTryShareAgain(){
+        return mTryShareAgain;
+    }
+
+    public void setTryShareAgain(boolean tryShareAgain) {
+       mTryShareAgain = tryShareAgain;
+    }
     
     public OperationsServiceBinder getOperationsServiceBinder() {
         return mOperationsServiceBinder;
@@ -356,15 +370,12 @@ implements OnRemoteOperationListener, ComponentsGetter {
     protected ServiceConnection newTransferenceServiceConnection() {
         return null;
     }
-    
 
     /**
      * Helper class handling a callback from the {@link AccountManager} after the creation of
      * a new ownCloud {@link Account} finished, successfully or not.
      * 
      * At this moment, only called after the creation of the first account.
-     * 
-     * @author David A. Velasco
      */
     public class AccountCreationCallback implements AccountManagerCallback<Bundle> {
 
@@ -454,10 +465,12 @@ implements OnRemoteOperationListener, ComponentsGetter {
             
             if (result.getCode() == ResultCode.UNAUTHORIZED) {
                 dismissLoadingDialog();
-                Toast t = Toast.makeText(this, ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()), 
+                Toast t = Toast.makeText(this, ErrorMessageAdapter.getErrorCauseMessage(result,
+                                operation, getResources()),
                         Toast.LENGTH_LONG);
                 t.show();
             }
+            mTryShareAgain = false;
 
         } else if (operation instanceof CreateShareOperation) {
             onCreateShareOperationFinish((CreateShareOperation) operation, result);
@@ -482,18 +495,36 @@ implements OnRemoteOperationListener, ComponentsGetter {
     }
     
 
-    private void onCreateShareOperationFinish(CreateShareOperation operation, RemoteOperationResult result) {
+    private void onCreateShareOperationFinish(CreateShareOperation operation,
+                                              RemoteOperationResult result) {
         dismissLoadingDialog();
         if (result.isSuccess()) {
+            mTryShareAgain = false;
             updateFileFromDB();
             
             Intent sendIntent = operation.getSendIntent();
             startActivity(sendIntent);
-            
-        } else { 
-            Toast t = Toast.makeText(this, ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()), 
-                    Toast.LENGTH_LONG);
-            t.show();
+        } else {
+            // Detect Failure (403) --> needs Password
+            if (result.getCode() == ResultCode.SHARE_FORBIDDEN) {
+                if (!isTryShareAgain()) {
+                    SharePasswordDialogFragment dialog =
+                            SharePasswordDialogFragment.newInstance(new OCFile(operation.getPath()),
+                                    operation.getSendIntent());
+                    dialog.show(getSupportFragmentManager(), DIALOG_SHARE_PASSWORD);
+                } else {
+                    Toast t = Toast.makeText(this,
+                        ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
+                        Toast.LENGTH_LONG);
+                    t.show();
+                    mTryShareAgain = false;
+                }
+            } else {
+                Toast t = Toast.makeText(this,
+                        ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()),
+                        Toast.LENGTH_LONG);
+                t.show();
+            }
         } 
     }
     
@@ -605,7 +636,7 @@ implements OnRemoteOperationListener, ComponentsGetter {
     @Override
     public FileUploaderBinder getFileUploaderBinder() {
         return mUploaderBinder;
-    };    
+    }
     
     
 }
index 7e60776..9c6f6dc 100644 (file)
@@ -1,6 +1,10 @@
-/* ownCloud Android client application
+/**
+ *   ownCloud Android client application
+ *
+ *   @author Bartek Przybylski
+ *   @author David A. Velasco
  *   Copyright (C) 2011  Bartek Przybylski
- *   Copyright (C) 2012-2014 ownCloud Inc.
+ *   Copyright (C) 2015 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,
 package com.owncloud.android.ui.activity;
 
 import java.io.File;
-import java.io.IOException;
 
 import android.accounts.Account;
 import android.accounts.AccountManager;
 import android.accounts.AuthenticatorException;
-import android.accounts.OperationCanceledException;
-import android.annotation.SuppressLint;
 import android.annotation.TargetApi;
 import android.app.AlertDialog;
 import android.app.Dialog;
@@ -96,7 +97,6 @@ import com.owncloud.android.operations.RefreshFolderOperation;
 import com.owncloud.android.operations.UnshareLinkOperation;
 import com.owncloud.android.services.observer.FileObserverService;
 import com.owncloud.android.syncadapter.FileSyncAdapter;
-import com.owncloud.android.ui.adapter.FileListListAdapter;
 import com.owncloud.android.ui.dialog.CreateFolderDialogFragment;
 import com.owncloud.android.ui.dialog.SslUntrustedCertDialog;
 import com.owncloud.android.ui.dialog.SslUntrustedCertDialog.OnSslUntrustedCertListener;
@@ -115,9 +115,6 @@ import com.owncloud.android.utils.UriUtils;
 
 /**
  * Displays, what files the user has available in his ownCloud.
- * 
- * @author Bartek Przybylski
- * @author David A. Velasco
  */
 
 public class FileDisplayActivity extends HookActivity implements
@@ -256,7 +253,7 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener {
             setNavigationListWithFolder(file);
             
             if (!stateWasRecovered) {
-                Log_OC.e(TAG, "Initializing Fragments in onAccountChanged..");
+                Log_OC.d(TAG, "Initializing Fragments in onAccountChanged..");
                 initFragmentsWithFile();
                 if (file.isFolder()) {
                     startSyncFolderOperation(file, false);
@@ -555,19 +552,19 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener {
     }
 
     private void startSynchronization() {
-        Log_OC.e(TAG, "Got to start sync");
+        Log_OC.d(TAG, "Got to start sync");
         if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.KITKAT) {
-            Log_OC.e(TAG, "Canceling all syncs for " + MainApp.getAuthority());
+            Log_OC.d(TAG, "Canceling all syncs for " + MainApp.getAuthority());
             ContentResolver.cancelSync(null, MainApp.getAuthority());   // cancel the current synchronizations of any ownCloud account
             Bundle bundle = new Bundle();
             bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
             bundle.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
-            Log_OC.e(TAG, "Requesting sync for " + getAccount().name + " at " + MainApp.getAuthority());
+            Log_OC.d(TAG, "Requesting sync for " + getAccount().name + " at " + MainApp.getAuthority());
             ContentResolver.requestSync(
                     getAccount(),
                     MainApp.getAuthority(), bundle);
         } else {
-            Log_OC.e(TAG, "Requesting sync for " + getAccount().name + " at " + MainApp.getAuthority() + " with new API");
+            Log_OC.d(TAG, "Requesting sync for " + getAccount().name + " at " + MainApp.getAuthority() + " with new API");
             SyncRequest.Builder builder = new SyncRequest.Builder();
             builder.setSyncAdapter(getAccount(), MainApp.getAuthority());
             builder.setExpedited(true);
@@ -649,6 +646,7 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener {
         if (filePaths != null) {
             String[] remotePaths = new String[filePaths.length];
             String remotePathBase = "";
+
             for (int j = mDirectories.getCount() - 2; j >= 0; --j) {
                 remotePathBase += OCFile.PATH_SEPARATOR + mDirectories.getItem(j);
             }
@@ -699,7 +697,7 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener {
 
         } finally {
             if (filepath == null) {
-                Log_OC.e(TAG, "Couldnt resolve path to file");
+                Log_OC.e(TAG, "Couldn't resolve path to file");
                 Toast t = Toast.makeText(this, getString(R.string.filedisplay_unexpected_bad_get_content), Toast.LENGTH_LONG);
                 t.show();
                 return;
@@ -786,7 +784,7 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener {
     @Override
     protected void onSaveInstanceState(Bundle outState) {
         // responsibility of restore is preferred in onCreate() before than in onRestoreInstanceState when there are Fragments involved
-        Log_OC.e(TAG, "onSaveInstanceState() start");
+        Log_OC.d(TAG, "onSaveInstanceState() start");
         super.onSaveInstanceState(outState);
         outState.putParcelable(FileDisplayActivity.KEY_WAITING_TO_PREVIEW, mWaitingToPreview);
         outState.putBoolean(FileDisplayActivity.KEY_SYNC_IN_PROGRESS, mSyncInProgress);
@@ -801,7 +799,7 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener {
     @Override
     protected void onResume() {
         super.onResume();
-        Log_OC.e(TAG, "onResume() start");
+        Log_OC.d(TAG, "onResume() start");
         
         // refresh list of files
         refreshListOfFilesFragment();
@@ -833,7 +831,7 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener {
 
     @Override
     protected void onPause() {
-        Log_OC.e(TAG, "onPause() start");
+        Log_OC.d(TAG, "onPause() start");
         if (mSyncBroadcastReceiver != null) {
             unregisterReceiver(mSyncBroadcastReceiver);
             //LocalBroadcastManager.getInstance(this).unregisterReceiver(mSyncBroadcastReceiver);
@@ -1110,40 +1108,34 @@ OnSslUntrustedCertListener, OnEnforceableRefreshListener {
                                     (synchResult.isException() && synchResult.getException() 
                                             instanceof AuthenticatorException))) {
 
-                            OwnCloudClient client = null;
+
                             try {
-                                OwnCloudAccount ocAccount = 
+                                OwnCloudClient client;
+                                OwnCloudAccount ocAccount =
                                         new OwnCloudAccount(getAccount(), context);
                                 client = (OwnCloudClientManagerFactory.getDefaultSingleton().
                                         removeClientFor(ocAccount));
-                                // TODO get rid of these exceptions
-                            } catch (AccountNotFoundException e) {
-                                e.printStackTrace();
-                            } catch (AuthenticatorException e) {
-                                e.printStackTrace();
-                            } catch (OperationCanceledException e) {
-                                e.printStackTrace();
-                            } catch (IOException e) {
-                                e.printStackTrace();
-                            }
-                            
-                            if (client != null) {
-                                OwnCloudCredentials cred = client.getCredentials();
-                                if (cred != null) {
-                                    AccountManager am = AccountManager.get(context);
-                                    if (cred.authTokenExpires()) {
-                                        am.invalidateAuthToken(
-                                                getAccount().type, 
-                                                cred.getAuthToken()
-                                        );
-                                    } else {
-                                        am.clearPassword(getAccount());
+
+                                if (client != null) {
+                                    OwnCloudCredentials cred = client.getCredentials();
+                                    if (cred != null) {
+                                        AccountManager am = AccountManager.get(context);
+                                        if (cred.authTokenExpires()) {
+                                            am.invalidateAuthToken(
+                                                    getAccount().type,
+                                                    cred.getAuthToken()
+                                            );
+                                        } else {
+                                            am.clearPassword(getAccount());
+                                        }
                                     }
                                 }
+                                requestCredentialsUpdate();
+
+                            } catch (AccountNotFoundException e) {
+                                Log_OC.e(TAG, "Account " + getAccount() + " was removed!", e);
                             }
-                            
-                            requestCredentialsUpdate();
-                            
+
                         }
                     }
                     removeStickyBroadcast(intent);
index e4b1886..3a61eb0 100644 (file)
@@ -1,5 +1,7 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2014 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   Copyright (C) 2015 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,
@@ -489,40 +491,33 @@ public class FolderPickerActivity extends FileActivity implements FileFragment.C
                                     (synchResult.isException() && synchResult.getException() 
                                             instanceof AuthenticatorException))) {
 
-                            OwnCloudClient client = null;
                             try {
-                                OwnCloudAccount ocAccount = 
+                                OwnCloudClient client;
+                                OwnCloudAccount ocAccount =
                                         new OwnCloudAccount(getAccount(), context);
                                 client = (OwnCloudClientManagerFactory.getDefaultSingleton().
                                         removeClientFor(ocAccount));
-                                // TODO get rid of these exceptions
-                            } catch (AccountNotFoundException e) {
-                                e.printStackTrace();
-                            } catch (AuthenticatorException e) {
-                                e.printStackTrace();
-                            } catch (OperationCanceledException e) {
-                                e.printStackTrace();
-                            } catch (IOException e) {
-                                e.printStackTrace();
-                            }
-                            
-                            if (client != null) {
-                                OwnCloudCredentials cred = client.getCredentials();
-                                if (cred != null) {
-                                    AccountManager am = AccountManager.get(context);
-                                    if (cred.authTokenExpires()) {
-                                        am.invalidateAuthToken(
-                                                getAccount().type, 
-                                                cred.getAuthToken()
-                                        );
-                                    } else {
-                                        am.clearPassword(getAccount());
+
+                                if (client != null) {
+                                    OwnCloudCredentials cred = client.getCredentials();
+                                    if (cred != null) {
+                                        AccountManager am = AccountManager.get(context);
+                                        if (cred.authTokenExpires()) {
+                                            am.invalidateAuthToken(
+                                                    getAccount().type,
+                                                    cred.getAuthToken()
+                                            );
+                                        } else {
+                                            am.clearPassword(getAccount());
+                                        }
                                     }
                                 }
+                                requestCredentialsUpdate();
+
+                            } catch (AccountNotFoundException e) {
+                                Log_OC.e(TAG, "Account " + getAccount() + " was removed!", e);
                             }
-                            
-                            requestCredentialsUpdate();
-                            
+
                         }
                     }
                     removeStickyBroadcast(intent);
index 901434e..0d4ab01 100644 (file)
@@ -1,5 +1,8 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2013 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
+ *   Copyright (C) 2015 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,
@@ -41,8 +44,6 @@ import com.owncloud.android.utils.DisplayUtils;
  * 
  * Added to show explanations for notifications when the user clicks on them, and there no place
  * better to show them.
- * 
- * @author David A. Velasco
  */
 public class GenericExplanationActivity  extends SherlockFragmentActivity {
 
index 54d65b1..daca8ad 100644 (file)
@@ -1,5 +1,7 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2014 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   Copyright (C) 2015 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,
index 793b3d9..5640404 100644 (file)
@@ -1,5 +1,7 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2013 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   Copyright (C) 2015 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,
index 22bdb18..d82f33b 100644 (file)
@@ -1,3 +1,24 @@
+
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
+ *   Copyright (C) 2015 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 android.support.v4.widget.SwipeRefreshLayout;
index 39b973d..76ece93 100644 (file)
@@ -1,5 +1,8 @@
-/* ownCloud Android client application
+/**
+ *   ownCloud Android client application
+ *
  *   Copyright (C) 2011 Bartek Przybylski
+ *   Copyright (C) 2015 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,
index 7a29073..d71968a 100644 (file)
@@ -1,6 +1,10 @@
-/* ownCloud Android client application
+/**
+ *   ownCloud Android client application
+ *
+ *   @author Bartek Przybylski
+ *   @author David A. Velasco
  *   Copyright (C) 2011  Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
+ *   Copyright (C) 2015 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,
@@ -21,13 +25,17 @@ import android.accounts.Account;
 import android.accounts.AccountManager;
 import android.accounts.AccountManagerCallback;
 import android.accounts.AccountManagerFuture;
+import android.content.ComponentName;
+import android.content.Context;
 import android.content.Intent;
+import android.content.ServiceConnection;
 import android.content.SharedPreferences;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.IBinder;
 import android.preference.CheckBoxPreference;
 import android.preference.Preference;
 import android.preference.Preference.OnPreferenceChangeListener;
@@ -50,20 +58,25 @@ import com.owncloud.android.MainApp;
 import com.owncloud.android.R;
 import com.owncloud.android.authentication.AccountUtils;
 import com.owncloud.android.authentication.AuthenticatorActivity;
+import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.db.DbHandler;
+import com.owncloud.android.files.FileOperationsHelper;
+import com.owncloud.android.files.services.FileDownloader;
+import com.owncloud.android.files.services.FileUploader;
 import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.services.OperationsService;
 import com.owncloud.android.ui.RadioButtonPreference;
 import com.owncloud.android.utils.DisplayUtils;
 
+import java.io.File;
+
 
 /**
  * An Activity that allows the user to change the application's settings.
- * 
- * @author Bartek Przybylski
- * @author David A. Velasco
  */
-public class Preferences extends SherlockPreferenceActivity implements AccountManagerCallback<Boolean> {
+public class Preferences extends SherlockPreferenceActivity
+        implements AccountManagerCallback<Boolean>, ComponentsGetter {
     
     private static final String TAG = "OwnCloudPreferences";
 
@@ -88,6 +101,9 @@ public class Preferences extends SherlockPreferenceActivity implements AccountMa
     private Preference mPrefInstantVideoUploadPathWiFi;
     private String mUploadVideoPath;
 
+    protected FileDownloader.FileDownloaderBinder mDownloaderBinder = null;
+    protected FileUploader.FileUploaderBinder mUploaderBinder = null;
+    private ServiceConnection mDownloadServiceConnection, mUploadServiceConnection = null;
 
     @SuppressWarnings("deprecation")
     @Override
@@ -199,13 +215,13 @@ public class Preferences extends SherlockPreferenceActivity implements AccountMa
                         String username = currentAccount.name.substring(0, currentAccount.name.lastIndexOf('@'));
                         
                         String recommendSubject = String.format(getString(R.string.recommend_subject), appName);
-                        String recommendText = String.format(getString(R.string.recommend_text), appName, downloadUrl, username);
+                        String recommendText = String.format(getString(R.string.recommend_text),
+                                appName, downloadUrl, username);
                         
                         intent.putExtra(Intent.EXTRA_SUBJECT, recommendSubject);
                         intent.putExtra(Intent.EXTRA_TEXT, recommendText);
                         startActivity(intent);
 
-
                         return(true);
 
                     }
@@ -337,6 +353,18 @@ public class Preferences extends SherlockPreferenceActivity implements AccountMa
        loadInstantUploadPath();
        loadInstantUploadVideoPath();
 
+        /* ComponentsGetter */
+        mDownloadServiceConnection = newTransferenceServiceConnection();
+        if (mDownloadServiceConnection != null) {
+            bindService(new Intent(this, FileDownloader.class), mDownloadServiceConnection,
+                    Context.BIND_AUTO_CREATE);
+        }
+        mUploadServiceConnection = newTransferenceServiceConnection();
+        if (mUploadServiceConnection != null) {
+            bindService(new Intent(this, FileUploader.class), mUploadServiceConnection,
+                    Context.BIND_AUTO_CREATE);
+        }
+
     }
     
     private void toggleInstantPictureOptions(Boolean value){
@@ -402,6 +430,7 @@ public class Preferences extends SherlockPreferenceActivity implements AccountMa
 
                     // Remove account
                     am.removeAccount(a, this, mHandler);
+                    Log_OC.d(TAG, "Remove an account " + a.name);
                 }
             }
         }
@@ -412,6 +441,18 @@ public class Preferences extends SherlockPreferenceActivity implements AccountMa
     @Override
     public void run(AccountManagerFuture<Boolean> future) {
         if (future.isDone()) {
+            // after remove account
+            Account account = new Account(mAccountName, MainApp.getAccountType());
+            if (!AccountUtils.exists(account, MainApp.getAppContext())) {
+                // Cancel tranfers
+                if (mUploaderBinder != null) {
+                    mUploaderBinder.cancel(account);
+                }
+                if (mDownloaderBinder != null) {
+                    mDownloaderBinder.cancel(account);
+                }
+            }
+
             Account a = AccountUtils.getCurrentOwnCloudAccount(this);
             String accountName = "";
             if (a == null) {
@@ -494,6 +535,16 @@ public class Preferences extends SherlockPreferenceActivity implements AccountMa
     @Override
     protected void onDestroy() {
         mDbHandler.close();
+
+        if (mDownloadServiceConnection != null) {
+            unbindService(mDownloadServiceConnection);
+            mDownloadServiceConnection = null;
+        }
+        if (mUploadServiceConnection != null) {
+            unbindService(mUploadServiceConnection);
+            mUploadServiceConnection = null;
+        }
+
         super.onDestroy();
     }
 
@@ -637,4 +688,65 @@ public class Preferences extends SherlockPreferenceActivity implements AccountMa
         editor.putString("instant_video_upload_path", mUploadVideoPath);
         editor.commit();
     }
+
+    // Methods for ComponetsGetter
+    @Override
+    public FileDownloader.FileDownloaderBinder getFileDownloaderBinder() {
+        return mDownloaderBinder;
+    }
+
+
+    @Override
+    public FileUploader.FileUploaderBinder getFileUploaderBinder() {
+        return mUploaderBinder;
+    }
+
+    @Override
+    public OperationsService.OperationsServiceBinder getOperationsServiceBinder() {
+        return null;
+    }
+
+    @Override
+    public FileDataStorageManager getStorageManager() {
+        return null;
+    }
+
+    @Override
+    public FileOperationsHelper getFileOperationsHelper() {
+        return null;
+    }
+
+    protected ServiceConnection newTransferenceServiceConnection() {
+        return new PreferencesServiceConnection();
+    }
+
+    /** Defines callbacks for service binding, passed to bindService() */
+    private class PreferencesServiceConnection implements ServiceConnection {
+
+        @Override
+        public void onServiceConnected(ComponentName component, IBinder service) {
+
+            if (component.equals(new ComponentName(Preferences.this, FileDownloader.class))) {
+                mDownloaderBinder = (FileDownloader.FileDownloaderBinder) service;
+
+            } else if (component.equals(new ComponentName(Preferences.this, FileUploader.class))) {
+                Log_OC.d(TAG, "Upload service connected");
+                mUploaderBinder = (FileUploader.FileUploaderBinder) service;
+            } else {
+                return;
+            }
+
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName component) {
+            if (component.equals(new ComponentName(Preferences.this, FileDownloader.class))) {
+                Log_OC.d(TAG, "Download service suddenly disconnected");
+                mDownloaderBinder = null;
+            } else if (component.equals(new ComponentName(Preferences.this, FileUploader.class))) {
+                Log_OC.d(TAG, "Upload service suddenly disconnected");
+                mUploaderBinder = null;
+            }
+        }
+    };
 }
index 0918572..7563ea6 100644 (file)
@@ -1,5 +1,8 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2013 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
+ *   Copyright (C) 2015 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,
@@ -48,9 +51,6 @@ import com.owncloud.android.utils.FileStorageUtils;
 /**
  * Displays local files and let the user choose what of them wants to upload
  * to the current ownCloud account
- * 
- * @author David A. Velasco
- * 
  */
 
 public class UploadFilesActivity extends FileActivity implements
@@ -289,8 +289,6 @@ public class UploadFilesActivity extends FileActivity implements
      * to upload into the ownCloud local folder.
      * 
      * Maybe an AsyncTask is not strictly necessary, but who really knows.
-     * 
-     * @author David A. Velasco
      */
     private class CheckAvailableSpaceTask extends AsyncTask<Void, Void, Boolean> {
 
index aa3b8aa..d1509f9 100644 (file)
@@ -1,5 +1,7 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2014 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   Copyright (C) 2015 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,
index 6efd6b4..8a01972 100644 (file)
@@ -1,6 +1,9 @@
-/* ownCloud Android client application
+/**
+ *   ownCloud Android client application
+ *
+ *   @author Bartek Przybylski
  *   Copyright (C) 2012  Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
+ *   Copyright (C) 2015 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,
@@ -75,9 +78,6 @@ import com.owncloud.android.utils.ErrorMessageAdapter;
 
 /**
  * This can be used to upload things to an ownCloud instance.
- * 
- * @author Bartek Przybylski
- * 
  */
 public class Uploader extends FileActivity implements OnItemClickListener, android.view.View.OnClickListener {
     private static final String TAG = "ownCloudUploader";
index b1c3263..2528cb2 100644 (file)
@@ -1,5 +1,9 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2014 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   @author masensio
+ *   @author David A. Velasco
+ *   Copyright (C) 2015 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,
@@ -25,9 +29,6 @@ import android.widget.TextView;
 
 /**
  * TODO
- * 
- * @author masensio
- * @author David A. Velasco
  *
  */
 public class CertificateCombinedExceptionViewAdapter implements SslUntrustedCertDialog.ErrorViewAdapter {
index 93efdf1..0f2536f 100644 (file)
@@ -1,5 +1,7 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2014 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   Copyright (C) 2015 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,
index df05ba4..2537d80 100644 (file)
@@ -1,6 +1,11 @@
-/* ownCloud Android client application\r
+/**\r
+ *   ownCloud Android client application\r
+ *\r
+ *   @author Bartek Przybylski\r
+ *   @author Tobias Kaminsky\r
+ *   @author David A. Velasco\r
  *   Copyright (C) 2011  Bartek Przybylski\r
- *   Copyright (C) 2012-2014 ownCloud Inc.\r
+ *   Copyright (C) 2015 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
@@ -30,10 +35,11 @@ import android.text.format.DateUtils;
 import android.view.LayoutInflater;\r
 import android.view.View;\r
 import android.view.ViewGroup;\r
+import android.widget.AbsListView;\r
 import android.widget.BaseAdapter;\r
+import android.widget.GridView;\r
 import android.widget.ImageView;\r
 import android.widget.ListAdapter;\r
-import android.widget.ListView;\r
 import android.widget.TextView;\r
 \r
 import com.owncloud.android.R;\r
@@ -52,22 +58,22 @@ import com.owncloud.android.utils.FileStorageUtils;
 /**\r
  * This Adapter populates a ListView with all files and folders in an ownCloud\r
  * instance.\r
- * \r
- * @author Bartek Przybylski\r
- * @author Tobias Kaminsky\r
- * @author David A. Velasco\r
  */\r
 public class FileListListAdapter extends BaseAdapter implements ListAdapter {\r
     private final static String PERMISSION_SHARED_WITH_ME = "S";\r
-    \r
+\r
     private Context mContext;\r
     private OCFile mFile = null;\r
     private Vector<OCFile> mFiles = null;\r
+    private Vector<OCFile> mFilesOrig = new Vector<OCFile>();\r
     private boolean mJustFolders;\r
 \r
     private FileDataStorageManager mStorageManager;\r
     private Account mAccount;\r
     private ComponentsGetter mTransferServiceGetter;\r
+    private boolean mGridMode;\r
+\r
+    private enum ViewType {LIST_ITEM, GRID_IMAGE, GRID_ITEM };\r
 \r
     private SharedPreferences mAppPreferences;\r
     \r
@@ -76,11 +82,10 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter {
             Context context,\r
             ComponentsGetter transferServiceGetter\r
             ) {\r
-\r
+        \r
         mJustFolders = justFolders;\r
         mContext = context;\r
         mAccount = AccountUtils.getCurrentOwnCloudAccount(mContext);\r
-\r
         mTransferServiceGetter = transferServiceGetter;\r
 \r
         mAppPreferences = PreferenceManager\r
@@ -94,6 +99,7 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter {
         // initialise thumbnails cache on background thread\r
         new ThumbnailsCacheManager.InitDiskCacheTask().execute();\r
 \r
+        mGridMode = false;\r
     }\r
     \r
     @Override\r
@@ -132,90 +138,156 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter {
 \r
     @Override\r
     public View getView(int position, View convertView, ViewGroup parent) {\r
+\r
         View view = convertView;\r
-        if (view == null) {\r
-            LayoutInflater inflator = (LayoutInflater) mContext\r
-                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);\r
-            view = inflator.inflate(R.layout.list_item, null);\r
-        }\r
-         \r
+        OCFile file = null;\r
+        LayoutInflater inflator = (LayoutInflater) mContext\r
+                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);\r
+\r
         if (mFiles != null && mFiles.size() > position) {\r
-            OCFile file = mFiles.get(position);\r
-            TextView fileName = (TextView) view.findViewById(R.id.Filename);           \r
-            String name = file.getFileName();\r
+            file = mFiles.get(position);\r
+        }\r
+\r
+        // Find out which layout should be displayed\r
+        ViewType viewType;\r
+        if (!mGridMode){\r
+            viewType = ViewType.LIST_ITEM;\r
+        } else if (file.isImage()){\r
+            viewType = ViewType.GRID_IMAGE;\r
+        } else {\r
+            viewType = ViewType.GRID_ITEM;\r
+        }\r
+\r
+        // Create View\r
+        switch (viewType){\r
+            case GRID_IMAGE:\r
+                view = inflator.inflate(R.layout.grid_image, null);\r
+                break;\r
+            case GRID_ITEM:\r
+                view = inflator.inflate(R.layout.grid_item, null);\r
+                break;\r
+            case LIST_ITEM:\r
+                view = inflator.inflate(R.layout.list_item, null);\r
+                break;\r
+        }\r
+\r
+        view.invalidate();\r
 \r
-            fileName.setText(name);\r
-            ImageView fileIcon = (ImageView) view.findViewById(R.id.imageView1);\r
+        if (file != null){\r
+\r
+            ImageView fileIcon = (ImageView) view.findViewById(R.id.thumbnail);\r
             fileIcon.setTag(file.getFileId());\r
-            ImageView sharedIconV = (ImageView) view.findViewById(R.id.sharedIcon);\r
-            ImageView sharedWithMeIconV = (ImageView) view.findViewById(R.id.sharedWithMeIcon);\r
-            sharedWithMeIconV.setVisibility(View.GONE);\r
-\r
-            ImageView localStateView = (ImageView) view.findViewById(R.id.imageView2);\r
-            localStateView.bringToFront();\r
-            FileDownloaderBinder downloaderBinder = mTransferServiceGetter.getFileDownloaderBinder();\r
-            FileUploaderBinder uploaderBinder = mTransferServiceGetter.getFileUploaderBinder();\r
-            boolean downloading = (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, file));\r
-            OperationsServiceBinder opsBinder = mTransferServiceGetter.getOperationsServiceBinder();\r
-            downloading |= (opsBinder != null && opsBinder.isSynchronizing(mAccount, file.getRemotePath()));\r
-            if (downloading) {\r
-                localStateView.setImageResource(R.drawable.downloading_file_indicator);\r
-                localStateView.setVisibility(View.VISIBLE);\r
-            } else if (uploaderBinder != null && uploaderBinder.isUploading(mAccount, file)) {\r
-                localStateView.setImageResource(R.drawable.uploading_file_indicator);\r
-                localStateView.setVisibility(View.VISIBLE);\r
-            } else if (file.isDown()) {\r
-                localStateView.setImageResource(R.drawable.local_file_indicator);\r
-                localStateView.setVisibility(View.VISIBLE);\r
-            } else {\r
-                localStateView.setVisibility(View.INVISIBLE);\r
+            TextView fileName;\r
+            String name;\r
+\r
+            switch (viewType){\r
+                case LIST_ITEM:\r
+                    TextView fileSizeV = (TextView) view.findViewById(R.id.file_size);\r
+                    TextView lastModV = (TextView) view.findViewById(R.id.last_mod);\r
+                    ImageView checkBoxV = (ImageView) view.findViewById(R.id.custom_checkbox);\r
+\r
+                    lastModV.setVisibility(View.VISIBLE);\r
+                    lastModV.setText(showRelativeTimestamp(file));\r
+\r
+                    checkBoxV.setVisibility(View.GONE);\r
+\r
+                    fileSizeV.setVisibility(View.VISIBLE);\r
+                    fileSizeV.setText(DisplayUtils.bytesToHumanReadable(file.getFileLength()));\r
+\r
+                    if (!file.isFolder()) {\r
+                        AbsListView parentList = (AbsListView)parent;\r
+                        if (parentList.getChoiceMode() == AbsListView.CHOICE_MODE_NONE) {\r
+                            checkBoxV.setVisibility(View.GONE);\r
+                        } else {\r
+                            if (parentList.isItemChecked(position)) {\r
+                                checkBoxV.setImageResource(android.R.drawable.checkbox_on_background);\r
+                            } else {\r
+                                checkBoxV.setImageResource(android.R.drawable.checkbox_off_background);\r
+                            }\r
+                            checkBoxV.setVisibility(View.VISIBLE);\r
+                        }\r
+\r
+                    } else { //Folder\r
+                        fileSizeV.setVisibility(View.INVISIBLE);\r
+                    }\r
+\r
+                case GRID_ITEM:\r
+                    // filename\r
+                    fileName = (TextView) view.findViewById(R.id.Filename);\r
+                    name = file.getFileName();\r
+                    fileName.setText(name);\r
+\r
+                case GRID_IMAGE:\r
+                    // sharedIcon\r
+                    ImageView sharedIconV = (ImageView) view.findViewById(R.id.sharedIcon);\r
+                    if (file.isShareByLink()) {\r
+                        sharedIconV.setVisibility(View.VISIBLE);\r
+                        sharedIconV.bringToFront();\r
+                    } else {\r
+                        sharedIconV.setVisibility(View.GONE);\r
+                    }\r
+\r
+                    // local state\r
+                    ImageView localStateView = (ImageView) view.findViewById(R.id.localFileIndicator);\r
+                    localStateView.bringToFront();\r
+                    FileDownloaderBinder downloaderBinder = mTransferServiceGetter.getFileDownloaderBinder();\r
+                    FileUploaderBinder uploaderBinder = mTransferServiceGetter.getFileUploaderBinder();\r
+                    boolean downloading = (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, file));\r
+                    OperationsServiceBinder opsBinder = mTransferServiceGetter.getOperationsServiceBinder();\r
+                    downloading |= (opsBinder != null && opsBinder.isSynchronizing(mAccount, file.getRemotePath()));\r
+                    if (downloading) {\r
+                        localStateView.setImageResource(R.drawable.downloading_file_indicator);\r
+                        localStateView.setVisibility(View.VISIBLE);\r
+                    } else if (uploaderBinder != null && uploaderBinder.isUploading(mAccount, file)) {\r
+                        localStateView.setImageResource(R.drawable.uploading_file_indicator);\r
+                        localStateView.setVisibility(View.VISIBLE);\r
+                    } else if (file.isDown()) {\r
+                        localStateView.setImageResource(R.drawable.local_file_indicator);\r
+                        localStateView.setVisibility(View.VISIBLE);\r
+                    } else {\r
+                        localStateView.setVisibility(View.INVISIBLE);\r
+                    }\r
+\r
+                    // share with me icon\r
+                    if (!file.isFolder()) {\r
+                        ImageView sharedWithMeIconV = (ImageView) view.findViewById(R.id.sharedWithMeIcon);\r
+                        sharedWithMeIconV.bringToFront();\r
+                        if (checkIfFileIsSharedWithMe(file)) {\r
+                            sharedWithMeIconV.setVisibility(View.VISIBLE);\r
+                        } else {\r
+                            sharedWithMeIconV.setVisibility(View.GONE);\r
+                        }\r
+                    }\r
+\r
+                    break;\r
             }\r
             \r
-            TextView fileSizeV = (TextView) view.findViewById(R.id.file_size);\r
-            TextView lastModV = (TextView) view.findViewById(R.id.last_mod);\r
-            ImageView checkBoxV = (ImageView) view.findViewById(R.id.custom_checkbox);\r
+            // For all Views\r
             \r
+            // this if-else is needed even though favorite icon is visible by default\r
+            // because android reuses views in listview\r
+            if (!file.keepInSync()) {\r
+                view.findViewById(R.id.favoriteIcon).setVisibility(View.GONE);\r
+            } else {\r
+                view.findViewById(R.id.favoriteIcon).setVisibility(View.VISIBLE);\r
+            }\r
+            \r
+            // No Folder\r
             if (!file.isFolder()) {\r
-                fileSizeV.setVisibility(View.VISIBLE);\r
-                fileSizeV.setText(DisplayUtils.bytesToHumanReadable(file.getFileLength()));\r
-                lastModV.setVisibility(View.VISIBLE);\r
-                lastModV.setText(showRelativeTimestamp(file));\r
-                // this if-else is needed even thoe fav icon is visible by default\r
-                // because android reuses views in listview\r
-                if (!file.keepInSync()) {\r
-                    view.findViewById(R.id.imageView3).setVisibility(View.GONE);\r
-                } else {\r
-                    view.findViewById(R.id.imageView3).setVisibility(View.VISIBLE);\r
-                }\r
-                \r
-                ListView parentList = (ListView)parent;\r
-                if (parentList.getChoiceMode() == ListView.CHOICE_MODE_NONE) { \r
-                    checkBoxV.setVisibility(View.GONE);\r
-                } else {\r
-                    if (parentList.isItemChecked(position)) {\r
-                        checkBoxV.setImageResource(android.R.drawable.checkbox_on_background);\r
-                    } else {\r
-                        checkBoxV.setImageResource(android.R.drawable.checkbox_off_background);\r
-                    }\r
-                    checkBoxV.setVisibility(View.VISIBLE);\r
-                }               \r
-                \r
-                // get Thumbnail if file is image\r
                 if (file.isImage() && file.getRemoteId() != null){\r
-                     // Thumbnail in Cache?\r
+                    // Thumbnail in Cache?\r
                     Bitmap thumbnail = ThumbnailsCacheManager.getBitmapFromDiskCache(\r
                             String.valueOf(file.getRemoteId())\r
-                    );\r
+                            );\r
                     if (thumbnail != null && !file.needsUpdateThumbnail()){\r
                         fileIcon.setImageBitmap(thumbnail);\r
                     } else {\r
-\r
                         // generate new Thumbnail\r
                         if (ThumbnailsCacheManager.cancelPotentialWork(file, fileIcon)) {\r
                             final ThumbnailsCacheManager.ThumbnailGenerationTask task =\r
                                     new ThumbnailsCacheManager.ThumbnailGenerationTask(\r
                                             fileIcon, mStorageManager, mAccount\r
-                                    );\r
+                                            );\r
                             if (thumbnail == null) {\r
                                 thumbnail = ThumbnailsCacheManager.mDefaultImg;\r
                             }\r
@@ -224,7 +296,7 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter {
                                     mContext.getResources(), \r
                                     thumbnail, \r
                                     task\r
-                            );\r
+                                    );\r
                             fileIcon.setImageDrawable(asyncDrawable);\r
                             task.execute(file);\r
                         }\r
@@ -232,45 +304,19 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter {
                 } else {\r
                     fileIcon.setImageResource(DisplayUtils.getFileTypeIconId(file.getMimetype(), file.getFileName()));\r
                 }\r
-\r
-                if (checkIfFileIsSharedWithMe(file)) {\r
-                    sharedWithMeIconV.setVisibility(View.VISIBLE);\r
-                }\r
-            } \r
-            else {\r
-                  // TODO Re-enable when server supports folder-size calculation\r
-//                if (FileStorageUtils.getDefaultSavePathFor(mAccount.name, file) != null){\r
-//                    fileSizeV.setVisibility(View.VISIBLE);\r
-//                    fileSizeV.setText(getFolderSizeHuman(FileStorageUtils.getDefaultSavePathFor(mAccount.name, file)));\r
-//                } else {\r
-                    fileSizeV.setVisibility(View.INVISIBLE);\r
-//                }\r
-\r
-                lastModV.setVisibility(View.VISIBLE);\r
-                lastModV.setText(showRelativeTimestamp(file));\r
-                checkBoxV.setVisibility(View.GONE);\r
-                view.findViewById(R.id.imageView3).setVisibility(View.GONE);\r
-\r
+            } else {\r
+                // Folder\r
                 if (checkIfFileIsSharedWithMe(file)) {\r
                     fileIcon.setImageResource(R.drawable.shared_with_me_folder);\r
-                    sharedWithMeIconV.setVisibility(View.VISIBLE);\r
+                } else if (file.isShareByLink()) {\r
+                    // If folder is sharedByLink, icon folder must be changed to\r
+                    // folder-public one\r
+                    fileIcon.setImageResource(R.drawable.folder_public);\r
                 } else {\r
                     fileIcon.setImageResource(\r
                             DisplayUtils.getFileTypeIconId(file.getMimetype(), file.getFileName())\r
                     );\r
                 }\r
-\r
-                // If folder is sharedByLink, icon folder must be changed to\r
-                // folder-public one\r
-                if (file.isShareByLink()) {\r
-                    fileIcon.setImageResource(R.drawable.folder_public);\r
-                }\r
-            }\r
-\r
-            if (file.isShareByLink()) {\r
-                sharedIconV.setVisibility(View.VISIBLE);\r
-            } else {\r
-                sharedIconV.setVisibility(View.GONE);\r
             }\r
         }\r
 \r
@@ -347,6 +393,9 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter {
         }\r
         if (mStorageManager != null) {\r
             mFiles = mStorageManager.getFolderContent(mFile);\r
+            mFilesOrig.clear();\r
+            mFilesOrig.addAll(mFiles);\r
+            \r
             if (mJustFolders) {\r
                 mFiles = getFolders(mFiles);\r
             }\r
@@ -404,10 +453,14 @@ public class FileListListAdapter extends BaseAdapter implements ListAdapter {
         mFiles = FileStorageUtils.sortFolder(mFiles);\r
         notifyDataSetChanged();\r
 \r
-    }    \r
+    }\r
     \r
     private CharSequence showRelativeTimestamp(OCFile file){\r
         return DisplayUtils.getRelativeDateTimeString(mContext, file.getModificationTimestamp(),\r
                 DateUtils.SECOND_IN_MILLIS, DateUtils.WEEK_IN_MILLIS, 0);\r
     }\r
+\r
+    public void setGridMode(boolean gridMode) {\r
+        mGridMode = gridMode;\r
+    }\r
 }\r
index 996851e..823abc5 100644 (file)
@@ -1,6 +1,9 @@
-/* ownCloud Android client application
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
  *   Copyright (C) 2011  Bartek Przybylski
- *   Copyright (C) 2012-2014 ownCloud Inc.
+ *   Copyright (C) 2015 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,
@@ -37,12 +40,11 @@ import com.owncloud.android.datamodel.ThumbnailsCacheManager;
 import com.owncloud.android.utils.BitmapUtils;
 import com.owncloud.android.utils.DisplayUtils;
 
+import third_parties.in.srain.cube.GridViewWithHeaderAndFooter;
+
 /**
  * This Adapter populates a ListView with all files and directories contained
  * in a local directory
- * 
- * @author David A. Velasco
- * 
  */
 public class LocalFileListAdapter extends BaseAdapter implements ListAdapter {
     
@@ -102,7 +104,7 @@ public class LocalFileListAdapter extends BaseAdapter implements ListAdapter {
             String name = file.getName();
             fileName.setText(name);
             
-            ImageView fileIcon = (ImageView) view.findViewById(R.id.imageView1);
+            ImageView fileIcon = (ImageView) view.findViewById(R.id.thumbnail);
             if (!file.isDirectory()) {
                 fileIcon.setImageResource(R.drawable.file);
             } else {
@@ -116,9 +118,10 @@ public class LocalFileListAdapter extends BaseAdapter implements ListAdapter {
             if (!file.isDirectory()) {
                 fileSizeV.setVisibility(View.VISIBLE);
                 fileSizeV.setText(DisplayUtils.bytesToHumanReadable(file.length()));
+
                 lastModV.setVisibility(View.VISIBLE);
                 lastModV.setText(DisplayUtils.unixTimeToHumanReadable(file.lastModified()));
-                ListView parentList = (ListView)parent;
+                ListView parentList = (ListView) parent;
                 if (parentList.getChoiceMode() == ListView.CHOICE_MODE_NONE) { 
                     checkBoxV.setVisibility(View.GONE);
                 } else {
@@ -166,9 +169,10 @@ public class LocalFileListAdapter extends BaseAdapter implements ListAdapter {
                 lastModV.setVisibility(View.GONE);
                 checkBoxV.setVisibility(View.GONE);
             }
-            
-            view.findViewById(R.id.imageView2).setVisibility(View.INVISIBLE);   // not GONE; the alignment would change
-            view.findViewById(R.id.imageView3).setVisibility(View.GONE);
+
+            // not GONE; the alignment changes; ugly way to keep it
+            view.findViewById(R.id.localFileIndicator).setVisibility(View.INVISIBLE);   
+            view.findViewById(R.id.favoriteIcon).setVisibility(View.GONE);
             
             view.findViewById(R.id.sharedIcon).setVisibility(View.GONE);
             view.findViewById(R.id.sharedWithMeIcon).setVisibility(View.GONE);
index ae4335e..b5664d5 100644 (file)
@@ -1,3 +1,22 @@
+/**
+ *   ownCloud Android client application
+ *
+ *   Copyright (C) 2015 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.adapter;
 
 import java.io.File;
index a944ead..7165614 100644 (file)
@@ -1,5 +1,9 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2014 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   @author masensio
+ *   @author David A. Velasco
+ *   Copyright (C) 2015 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,
@@ -27,9 +31,6 @@ import android.widget.TextView;
 
 /**
  * TODO
- * 
- * @author masensio
- * @author David A. Velasco
  */
 public class SslCertificateViewAdapter implements SslUntrustedCertDialog.CertificateViewAdapter {
     
index 7d2e291..7ac7144 100644 (file)
@@ -1,5 +1,9 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2014 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   @author masensio
+ *   @author David A. Velasco
+ *   Copyright (C) 2015 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,
@@ -24,10 +28,6 @@ import android.widget.TextView;
 
 /**
  * Dialog to show an Untrusted Certificate
- * 
- * @author masensio
- * @author David A. Velasco
- *
  */
 public class SslErrorViewAdapter implements SslUntrustedCertDialog.ErrorViewAdapter {
     
index a290dca..1c8c8c2 100644 (file)
@@ -1,5 +1,9 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2014 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   @author masensio
+ *   @author David A. Velasco
+ *   Copyright (C) 2015 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,
@@ -31,9 +35,6 @@ import android.view.View;
 import android.widget.TextView;
 
 /**
- * 
- * @author masensio
- * @author David A. Velasco
  *
  */
 public class X509CertificateViewAdapter implements SslUntrustedCertDialog.CertificateViewAdapter {
index eef9d09..24d7bc2 100644 (file)
@@ -1,5 +1,7 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2013 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   Copyright (C) 2015 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,
index a9307b9..29ed390 100644 (file)
@@ -1,6 +1,8 @@
-/* ownCloud Android client application
+/**
+ *   ownCloud Android client application
+ *
  *   Copyright (C) 2012 Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
+ *   Copyright (C) 2015 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,
index 91cfbfd..6cf229d 100644 (file)
@@ -1,6 +1,9 @@
-/* ownCloud Android client application
+/**
+ *   ownCloud Android client application
+ *
+ *   @author Bartek Przybylski
  *   Copyright (C) 2012 Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
+ *   Copyright (C) 2015 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,
@@ -33,9 +36,6 @@ import com.owncloud.android.utils.DisplayUtils;
 
 /**
  * Dialog which will be displayed to user upon keep-in-sync file conflict.
- * 
- * @author Bartek Przybylski
- *
  */
 public class ConflictsResolveDialog extends SherlockDialogFragment {
 
index 29b3be2..170fe08 100644 (file)
@@ -1,5 +1,8 @@
-/* ownCloud Android client application
- *   Copyright (C) 2014 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
+ *   Copyright (C) 2015 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,
@@ -37,9 +40,7 @@ import android.widget.Toast;
 /**
  *  Dialog to input the name for a new folder to create.  
  * 
- *  Triggers the folder creation when name is confirmed. 
- *  
- *  @author David A. Velasco
+ *  Triggers the folder creation when name is confirmed.
  */
 public class CreateFolderDialogFragment 
 extends SherlockDialogFragment implements DialogInterface.OnClickListener {
index 080316b..1b99c7b 100644 (file)
@@ -1,5 +1,7 @@
-/* ownCloud Android client application
- *   Copyright (C) 2014 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   Copyright (C) 2015 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,
index dbd3d99..32fa4c6 100644 (file)
@@ -1,5 +1,7 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2013 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   Copyright (C) 2015 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,
index d0dcfb7..e8e68e7 100644 (file)
@@ -1,5 +1,7 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2014 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   Copyright (C) 2015 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,
index 2453404..c3b7ed1 100644 (file)
@@ -1,5 +1,8 @@
-/* ownCloud Android client application
- *   Copyright (C) 2014 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
+ *   Copyright (C) 2015 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,
@@ -20,9 +23,7 @@ package com.owncloud.android.ui.dialog;
 /**
  *  Dialog requiring confirmation before removing a given OCFile.  
  * 
- *  Triggers the removal according to the user response. 
- *  
- *  @author David A. Velasco
+ *  Triggers the removal according to the user response.
  */
 import java.util.Vector;
 
index d285f1e..0e7850b 100644 (file)
@@ -1,4 +1,7 @@
-/* ownCloud Android client application
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
  *   Copyright (C) 2014 ownCloud Inc.
  *
  *   This program is free software: you can redistribute it and/or modify
@@ -43,9 +46,7 @@ import com.owncloud.android.ui.activity.ComponentsGetter;
 /**
  *  Dialog to input a new name for a file or folder to rename.  
  * 
- *  Triggers the rename operation when name is confirmed. 
- *  
- *  @author David A. Velasco
+ *  Triggers the rename operation when name is confirmed.
  */
 public class RenameFileDialogFragment
 extends SherlockDialogFragment implements DialogInterface.OnClickListener {
index 76243ed..31d1d2d 100644 (file)
@@ -1,5 +1,9 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2014 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   @author Maria Asensio
+ *   @author David A. Velasco
+ *   Copyright (C) 2015 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,
@@ -44,9 +48,6 @@ import com.owncloud.android.lib.common.utils.Log_OC;
 
 /**
  * Dialog to show the WebView for SAML Authentication
- * 
- * @author Maria Asensio
- * @author David A. Velasco
  */
 public class SamlWebViewDialog extends SherlockDialogFragment {
 
@@ -76,7 +77,6 @@ public class SamlWebViewDialog extends SherlockDialogFragment {
      * @return              New dialog instance, ready to show.
      */
     public static SamlWebViewDialog newInstance(String url, String targetUrl) {
-        Log_OC.d(TAG, "New instance");
         SamlWebViewDialog fragment = new SamlWebViewDialog();
         Bundle args = new Bundle();
         args.putString(ARG_INITIAL_URL, url);
@@ -88,13 +88,12 @@ public class SamlWebViewDialog extends SherlockDialogFragment {
     
     public SamlWebViewDialog() {
         super();
-        Log_OC.d(TAG, "constructor");
     }
     
     
     @Override
     public void onAttach(Activity activity) {
-        Log_OC.d(TAG, "onAttach");
+        Log_OC.v(TAG, "onAttach");
         super.onAttach(activity);
         try {
             mSsoWebViewClientListener = (SsoWebViewClientListener) activity;
@@ -110,7 +109,7 @@ public class SamlWebViewDialog extends SherlockDialogFragment {
     @SuppressLint("SetJavaScriptEnabled")
     @Override
     public void onCreate(Bundle savedInstanceState) {
-        Log_OC.d(TAG, "onCreate, savedInstanceState is " + savedInstanceState);
+        Log_OC.v(TAG, "onCreate, savedInstanceState is " + savedInstanceState);
         super.onCreate(savedInstanceState);
         
         setRetainInstance(true);
@@ -132,7 +131,7 @@ public class SamlWebViewDialog extends SherlockDialogFragment {
     @SuppressLint("SetJavaScriptEnabled")
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
-        Log_OC.d(TAG, "onCreateView, savedInsanceState is " + savedInstanceState);
+        Log_OC.v(TAG, "onCreateView, savedInsanceState is " + savedInstanceState);
         
         // Inflate layout of the dialog  
         RelativeLayout ssoRootView = (RelativeLayout) inflater.inflate(R.layout.sso_dialog, container, false);  // null parent view because it will go in the dialog layout
@@ -144,11 +143,6 @@ public class SamlWebViewDialog extends SherlockDialogFragment {
             mSsoWebView.setFocusableInTouchMode(true);
             mSsoWebView.setClickable(true);
             
-            CookieManager cookieManager = CookieManager.getInstance();
-            cookieManager.setAcceptCookie(true);
-            cookieManager.removeAllCookie();
-            mSsoWebView.loadUrl(mInitialUrl);
-          
             WebSettings webSettings = mSsoWebView.getSettings();
             webSettings.setJavaScriptEnabled(true);
             webSettings.setBuiltInZoomControls(false);
@@ -156,6 +150,12 @@ public class SamlWebViewDialog extends SherlockDialogFragment {
             webSettings.setSavePassword(false);
             webSettings.setUserAgentString(OwnCloudClient.USER_AGENT);
             webSettings.setSaveFormData(false);
+            
+            CookieManager cookieManager = CookieManager.getInstance();
+            cookieManager.setAcceptCookie(true);
+            cookieManager.removeAllCookie();
+            
+            mSsoWebView.loadUrl(mInitialUrl);
         }
         
         mWebViewClient.setTargetUrl(mTargetUrl);
@@ -174,7 +174,7 @@ public class SamlWebViewDialog extends SherlockDialogFragment {
 
     @Override
     public void onSaveInstanceState(Bundle outState) {
-        Log_OC.d(TAG, "onSaveInstanceState being CALLED");
+        Log_OC.v(TAG, "onSaveInstanceState being CALLED");
         super.onSaveInstanceState(outState);
         
         // save URLs
@@ -184,7 +184,7 @@ public class SamlWebViewDialog extends SherlockDialogFragment {
 
     @Override
     public void onDestroyView() {
-        Log_OC.d(TAG, "onDestroyView");
+        Log_OC.v(TAG, "onDestroyView");
         
         if ((ViewGroup)mSsoWebView.getParent() != null) {
             ((ViewGroup)mSsoWebView.getParent()).removeView(mSsoWebView);
@@ -196,8 +196,6 @@ public class SamlWebViewDialog extends SherlockDialogFragment {
         Dialog dialog = getDialog();
         if ((dialog != null)) {
             dialog.setOnDismissListener(null);
-            //dialog.dismiss();
-            //dialog.setDismissMessage(null);
         }
         
         super.onDestroyView();
@@ -205,13 +203,13 @@ public class SamlWebViewDialog extends SherlockDialogFragment {
     
     @Override
     public void onDestroy() {
-        Log_OC.d(TAG, "onDestroy");
+        Log_OC.v(TAG, "onDestroy");
         super.onDestroy();
     }
 
     @Override
     public void onDetach() {
-        Log_OC.d(TAG, "onDetach");
+        Log_OC.v(TAG, "onDetach");
         mSsoWebViewClientListener = null;
         mWebViewClient = null;
         super.onDetach();
@@ -231,39 +229,39 @@ public class SamlWebViewDialog extends SherlockDialogFragment {
     
     @Override
     public void onStart() {
-        Log_OC.d(TAG, "onStart");
+        Log_OC.v(TAG, "onStart");
         super.onStart();
     }
 
     @Override
     public void onStop() {
-        Log_OC.d(TAG, "onStop");
+        Log_OC.v(TAG, "onStop");
         super.onStop();
     }
 
     @Override
     public void onResume() {
-        Log_OC.d(TAG, "onResume");
+        Log_OC.v(TAG, "onResume");
         super.onResume();
         mSsoWebView.onResume();
     }
 
     @Override
     public void onPause() {
-        Log_OC.d(TAG, "onPause");
+        Log_OC.v(TAG, "onPause");
         mSsoWebView.onPause();
         super.onPause();
     }
     
     @Override
     public int show (FragmentTransaction transaction, String tag) {
-        Log_OC.d(TAG, "show (transaction)");
+        Log_OC.v(TAG, "show (transaction)");
         return super.show(transaction, tag);
     }
 
     @Override
     public void show (FragmentManager manager, String tag) {
-        Log_OC.d(TAG, "show (manager)");
+        Log_OC.v(TAG, "show (manager)");
         super.show(manager, tag);
     }
     
index 2876f7b..fc88e5d 100644 (file)
@@ -1,5 +1,8 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2014 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
+ *   Copyright (C) 2015 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,
@@ -50,8 +53,6 @@ import com.owncloud.android.ui.activity.FileActivity;
 /**
  * Dialog showing a list activities able to resolve a given Intent, 
  * filtering out the activities matching give package names.
- * 
- * @author David A. Velasco
  */
 public class ShareLinkToDialog  extends SherlockDialogFragment {
     
@@ -146,7 +147,7 @@ public class ShareLinkToDialog  extends SherlockDialogFragment {
                             } else {
                                 // Create a new share resource
                                 ((ComponentsGetter)getSherlockActivity()).getFileOperationsHelper()
-                                    .shareFileWithLinkToApp(mFile, mIntent);
+                                    .shareFileWithLinkToApp(mFile, "", mIntent);
                             }
                         }
         })
diff --git a/src/com/owncloud/android/ui/dialog/SharePasswordDialogFragment.java b/src/com/owncloud/android/ui/dialog/SharePasswordDialogFragment.java
new file mode 100644 (file)
index 0000000..d8f507b
--- /dev/null
@@ -0,0 +1,124 @@
+/**
+ *   ownCloud Android client application
+ *   @author masensio
+ *   Copyright (C) 2015 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.dialog;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.actionbarsherlock.app.SherlockDialogFragment;
+import com.owncloud.android.R;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.ui.activity.FileActivity;
+
+/**
+ * Dialog to input the password for sharing a file/folder.
+ *
+ * Triggers the share when the password is introduced.
+ */
+
+public class SharePasswordDialogFragment extends SherlockDialogFragment
+        implements DialogInterface.OnClickListener {
+
+    private static final String ARG_FILE = "FILE";
+    private static final String ARG_SEND_INTENT = "SEND_INTENT";
+
+    public static final String PASSWORD_FRAGMENT = "PASSWORD_FRAGMENT";
+
+    private OCFile mFile;
+    private Intent mSendIntent;
+
+    /**
+     * Public factory method to create new SharePasswordDialogFragment instances.
+     *
+     * @param file
+     * @param sendIntent
+     * @return              Dialog ready to show.
+     */
+    public static SharePasswordDialogFragment newInstance(OCFile file, Intent sendIntent) {
+        SharePasswordDialogFragment frag = new SharePasswordDialogFragment();
+        Bundle args = new Bundle();
+        args.putParcelable(ARG_FILE, file);
+        args.putParcelable(ARG_SEND_INTENT, sendIntent);
+        frag.setArguments(args);
+        return frag;
+    }
+
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        mFile = getArguments().getParcelable(ARG_FILE);
+        mSendIntent = getArguments().getParcelable(ARG_SEND_INTENT);
+
+        // Inflate the layout for the dialog
+        LayoutInflater inflater = getActivity().getLayoutInflater();
+        View v = inflater.inflate(R.layout.password_dialog, null);
+
+        // Setup layout
+        EditText inputText = ((EditText)v.findViewById(R.id.share_password));
+        inputText.setText("");
+        inputText.requestFocus();
+
+        // Build the dialog
+        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+        builder.setView(v)
+               .setPositiveButton(R.string.common_ok, this)
+               .setNegativeButton(R.string.common_cancel, this)
+               .setTitle(R.string.share_link_password_title);
+        Dialog d = builder.create();
+        d.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
+        return d;
+    }
+
+
+    @Override
+    public void onClick(DialogInterface dialog, int which) {
+        if (which == AlertDialog.BUTTON_POSITIVE) {
+            // Enable the flag "Share again"
+            ((FileActivity) getSherlockActivity()).setTryShareAgain(true);
+
+            String password =
+                    ((TextView)(getDialog().findViewById(R.id.share_password)))
+                        .getText().toString();
+
+            if (password.length() <= 0) {
+                Toast.makeText(
+                        getActivity(),
+                        R.string.share_link_empty_password,
+                        Toast.LENGTH_LONG).show();
+                return;
+            }
+
+            // Share the file
+            ((FileActivity)getSherlockActivity()).getFileOperationsHelper()
+                                    .shareFileWithLinkToApp(mFile, password, mSendIntent);
+
+        } else {
+            // Disable the flag "Share again"
+            ((FileActivity) getSherlockActivity()).setTryShareAgain(false);
+        }
+    }
+}
index 167177b..6658260 100644 (file)
@@ -1,5 +1,9 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2014 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   @author masensio
+ *   @author David A. Velasco
+ *   Copyright (C) 2015 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,
@@ -47,10 +51,7 @@ import com.owncloud.android.ui.adapter.X509CertificateViewAdapter;
  * to decide trust on it or not.
  * 
  * Abstract implementation of common functionality for different dialogs that
- * get the information about the error and the certificate from different classes. 
- * 
- * @author masensio
- * @author David A. Velasco
+ * get the information about the error and the certificate from different classes.
  */
 public class SslUntrustedCertDialog extends SherlockDialogFragment {
     
index db20a5c..1e31c0c 100644 (file)
@@ -1,5 +1,8 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2013 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
+ *   Copyright (C) 2015 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,
@@ -46,8 +49,6 @@ import com.owncloud.android.lib.common.utils.Log_OC;
 
 /**
  * Dialog to request the user about a certificate that could not be validated with the certificates store in the system.
- * 
- * @author David A. Velasco
  */
 public class SslValidatorDialog extends Dialog {
 
index 3a71139..dae43f8 100644 (file)
@@ -1,5 +1,7 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2013 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   Copyright (C) 2015 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,
index f096103..1552da1 100644 (file)
@@ -1,6 +1,8 @@
-/* ownCloud Android client application
+/**
+ *   ownCloud Android client application
+ *
  *   Copyright (C) 2012 Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
+ *   Copyright (C) 2015 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,
index 5abf55d..5a8da70 100644 (file)
@@ -1,6 +1,8 @@
-/* ownCloud Android client application
+/**
+ *   ownCloud Android client application
+ *
  *   Copyright (C) 2012 Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
+ *   Copyright (C) 2015 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,
index 1b7a1dd..03289cf 100644 (file)
@@ -1,6 +1,8 @@
-/* ownCloud Android client application
+/**
+ *   ownCloud Android client application
+ *
  *   Copyright (C) 2012 Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
+ *   Copyright (C) 2012-2015 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,
@@ -20,15 +22,17 @@ package com.owncloud.android.ui.fragment;
 
 import java.util.ArrayList;
 
+import android.content.Context;
 import android.os.Bundle;
 import android.support.v4.widget.SwipeRefreshLayout;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.widget.AbsListView;
 import android.widget.AdapterView;
 import android.widget.AdapterView.OnItemClickListener;
+import android.widget.GridView;
 import android.widget.ListAdapter;
-import android.widget.ListView;
 import android.widget.TextView;
 
 import com.actionbarsherlock.app.SherlockFragment;
@@ -36,6 +40,9 @@ import com.owncloud.android.R;
 import com.owncloud.android.lib.common.utils.Log_OC;
 import com.owncloud.android.ui.ExtendedListView;
 import com.owncloud.android.ui.activity.OnEnforceableRefreshListener;
+import com.owncloud.android.ui.adapter.FileListListAdapter;
+
+import third_parties.in.srain.cube.GridViewWithHeaderAndFooter;
 
 /**
  * TODO extending SherlockListFragment instead of SherlockFragment
@@ -52,9 +59,8 @@ implements OnItemClickListener, OnEnforceableRefreshListener {
     private static final String KEY_HEIGHT_CELL = "HEIGHT_CELL";
     private static final String KEY_EMPTY_LIST_MESSAGE = "EMPTY_LIST_MESSAGE";
 
-    protected ExtendedListView mList;
-
-    private SwipeRefreshLayout mRefreshLayout;
+    private SwipeRefreshLayout mRefreshListLayout;
+    private SwipeRefreshLayout mRefreshGridLayout;
     private SwipeRefreshLayout mRefreshEmptyLayout;
     private TextView mEmptyListMessage;
     
@@ -66,46 +72,98 @@ implements OnItemClickListener, OnEnforceableRefreshListener {
 
     private OnEnforceableRefreshListener mOnRefreshListener = null;
     
-    
-    public void setListAdapter(ListAdapter listAdapter) {
-        mList.setAdapter(listAdapter);
-        mList.invalidate();
+    protected AbsListView mCurrentListView;
+    private ExtendedListView mListView;
+    private View mListFooterView;
+    private GridViewWithHeaderAndFooter mGridView;
+    private View mGridFooterView;
+
+    private ListAdapter mAdapter;
+
+
+    protected void setListAdapter(ListAdapter listAdapter) {
+        mAdapter = listAdapter;
+        mCurrentListView.setAdapter(listAdapter);
+        mCurrentListView.invalidate();
     }
 
-    public void setFooterView(View footer) {
-        mList.addFooterView(footer, null, false);
-        mList.invalidate();
+    protected AbsListView getListView() {
+        return mCurrentListView;
     }
 
-    public ListView getListView() {
-        return mList;
+
+    protected void switchToGridView() {
+        if ((mCurrentListView == mListView)) {
+
+            mListView.setAdapter(null);
+            mRefreshListLayout.setVisibility(View.GONE);
+
+            if (mAdapter instanceof FileListListAdapter) {
+                ((FileListListAdapter) mAdapter).setGridMode(true);
+            }
+            mGridView.setAdapter(mAdapter);
+            mRefreshGridLayout.setVisibility(View.VISIBLE);
+
+            mCurrentListView = mGridView;
+        }
     }
+    
+    protected void switchToListView() {
+        if (mCurrentListView == mGridView) {
+            mGridView.setAdapter(null);
+            mRefreshGridLayout.setVisibility(View.GONE);
+
+            if (mAdapter instanceof FileListListAdapter) {
+                ((FileListListAdapter) mAdapter).setGridMode(false);
+            }
+            mListView.setAdapter(mAdapter);
+            mRefreshListLayout.setVisibility(View.VISIBLE);
 
+            mCurrentListView = mListView;
+        }
+    }
+    
+    
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
-        Log_OC.e(TAG, "onCreateView");
+        Log_OC.d(TAG, "onCreateView");
 
         View v = inflater.inflate(R.layout.list_fragment, null);
-        mEmptyListMessage = (TextView) v.findViewById(R.id.empty_list_view);
-        mList = (ExtendedListView) (v.findViewById(R.id.list_root));
-        mList.setOnItemClickListener(this);
 
-        mList.setDivider(getResources().getDrawable(R.drawable.uploader_list_separator));
-        mList.setDividerHeight(1);
+        mListView = (ExtendedListView)(v.findViewById(R.id.list_root));
+        mListView.setOnItemClickListener(this);
+        mListFooterView = inflater.inflate(R.layout.list_footer, null, false);
+
+        mGridView = (GridViewWithHeaderAndFooter) (v.findViewById(R.id.grid_root));
+        mGridView.setNumColumns(GridView.AUTO_FIT);
+        mGridView.setOnItemClickListener(this);
+        mGridFooterView = inflater.inflate(R.layout.list_footer, null, false);
 
         if (savedInstanceState != null) {
             int referencePosition = savedInstanceState.getInt(KEY_SAVED_LIST_POSITION);
-            setReferencePosition(referencePosition);
+            if (mCurrentListView == mListView) {
+                Log_OC.v(TAG, "Setting and centering around list position " + referencePosition);
+                mListView.setAndCenterSelection(referencePosition);
+            } else {
+                Log_OC.v(TAG, "Setting grid position " + referencePosition);
+                mGridView.setSelection(referencePosition);
+            }
         }
 
-        // Pull down refresh
-        mRefreshLayout = (SwipeRefreshLayout) v.findViewById(R.id.swipe_refresh_files);
-        mRefreshEmptyLayout = (SwipeRefreshLayout) v.findViewById(R.id.swipe_refresh_files_emptyView);
+        // Pull-down to refresh layout
+        mRefreshListLayout = (SwipeRefreshLayout) v.findViewById(R.id.swipe_containing_list);
+        mRefreshGridLayout = (SwipeRefreshLayout) v.findViewById(R.id.swipe_containing_grid);
+        mRefreshEmptyLayout = (SwipeRefreshLayout) v.findViewById(R.id.swipe_containing_empty);
+        mEmptyListMessage = (TextView) v.findViewById(R.id.empty_list_view);
         
-        onCreateSwipeToRefresh(mRefreshLayout);
+        onCreateSwipeToRefresh(mRefreshListLayout);
+        onCreateSwipeToRefresh(mRefreshGridLayout);
         onCreateSwipeToRefresh(mRefreshEmptyLayout);
-        
-        mList.setEmptyView(mRefreshEmptyLayout);
+
+        mListView.setEmptyView(mRefreshEmptyLayout);
+        mGridView.setEmptyView(mRefreshEmptyLayout);
+
+        mCurrentListView = mListView;   // list as default
 
         return v;
     }
@@ -136,7 +194,7 @@ implements OnItemClickListener, OnEnforceableRefreshListener {
     @Override
     public void onSaveInstanceState(Bundle savedInstanceState) {
         super.onSaveInstanceState(savedInstanceState);
-        Log_OC.e(TAG, "onSaveInstanceState()");
+        Log_OC.d(TAG, "onSaveInstanceState()");
         savedInstanceState.putInt(KEY_SAVED_LIST_POSITION, getReferencePosition());
         savedInstanceState.putIntegerArrayList(KEY_INDEXES, mIndexes);
         savedInstanceState.putIntegerArrayList(KEY_FIRST_POSITIONS, mFirstPositions);
@@ -150,32 +208,20 @@ implements OnItemClickListener, OnEnforceableRefreshListener {
      * reposition the visible items in the list when the device is turned to
      * other position.
      * 
-     * THe current policy is take as a reference the visible item in the center
+     * The current policy is take as a reference the visible item in the center
      * of the screen.
      * 
      * @return The position in the list of the visible item in the center of the
      *         screen.
      */
     protected int getReferencePosition() {
-        if (mList != null) {
-            return (mList.getFirstVisiblePosition() + mList.getLastVisiblePosition()) / 2;
+        if (mCurrentListView != null) {
+            return (mCurrentListView.getFirstVisiblePosition() + mCurrentListView.getLastVisiblePosition()) / 2;
         } else {
             return 0;
         }
     }
 
-    /**
-     * Sets the visible part of the list from the reference position.
-     * 
-     * @param position Reference position previously returned by
-     *            {@link LocalFileListFragment#getReferencePosition()}
-     */
-    protected void setReferencePosition(int position) {
-        if (mList != null) {
-            mList.setAndCenterSelection(position);
-        }
-    }
-
 
     /*
      * Restore index and position
@@ -185,28 +231,28 @@ implements OnItemClickListener, OnEnforceableRefreshListener {
             // needs to be checked; not every browse-up had a browse-down before 
             
             int index = mIndexes.remove(mIndexes.size() - 1);
-            
-            int firstPosition = mFirstPositions.remove(mFirstPositions.size() -1);
-            
+            final int firstPosition = mFirstPositions.remove(mFirstPositions.size() -1);
             int top = mTops.remove(mTops.size() - 1);
-            
-            mList.setSelectionFromTop(firstPosition, top);
-            
-            // Move the scroll if the selection is not visible
-            int indexPosition = mHeightCell*index;
-            int height = mList.getHeight();
-            
-            if (indexPosition > height) {
-                if (android.os.Build.VERSION.SDK_INT >= 11)
-                {
-                    mList.smoothScrollToPosition(index); 
+
+            Log_OC.v(TAG, "Setting selection to position: " + firstPosition + "; top: " + top + "; index: " + index);
+
+            if (mCurrentListView == mListView) {
+                if (mHeightCell*index <= mListView.getHeight()) {
+                    mListView.setSelectionFromTop(firstPosition, top);
+                } else {
+                    mListView.setSelectionFromTop(index, 0);
                 }
-                else if (android.os.Build.VERSION.SDK_INT >= 8)
-                {
-                    mList.setSelectionFromTop(index, 0);
+
+            } else {
+                if (mHeightCell*index <= mGridView.getHeight()) {
+                    mGridView.setSelection(firstPosition);
+                    //mGridView.smoothScrollToPosition(firstPosition);
+                } else {
+                    mGridView.setSelection(index);
+                    //mGridView.smoothScrollToPosition(index);
                 }
-                
             }
+
         }
     }
     
@@ -217,10 +263,10 @@ implements OnItemClickListener, OnEnforceableRefreshListener {
         
         mIndexes.add(index);
         
-        int firstPosition = mList.getFirstVisiblePosition();
+        int firstPosition = mCurrentListView.getFirstVisiblePosition();
         mFirstPositions.add(firstPosition);
         
-        View view = mList.getChildAt(0);
+        View view = mCurrentListView.getChildAt(0);
         int top = (view == null) ? 0 : view.getTop() ;
 
         mTops.add(top);
@@ -237,10 +283,10 @@ implements OnItemClickListener, OnEnforceableRefreshListener {
 
     @Override
     public void onRefresh() {
-        // to be @overriden
-        mRefreshLayout.setRefreshing(false);
+        mRefreshListLayout.setRefreshing(false);
+        mRefreshGridLayout.setRefreshing(false);
         mRefreshEmptyLayout.setRefreshing(false);
-        
+
         if (mOnRefreshListener != null) {
             mOnRefreshListener.onRefresh();
         }
@@ -251,32 +297,18 @@ implements OnItemClickListener, OnEnforceableRefreshListener {
     
 
     /**
-     * Enables swipe gesture
-     */
-    public void enableSwipe() {
-        mRefreshLayout.setEnabled(true);
-    }
-    /**
-     * Disables swipe gesture. It prevents manual gestures but keeps the option you show
-     * refreshing programmatically.
-     */
-    public void disableSwipe() {
-        mRefreshLayout.setEnabled(false);
-    }
-    
-    /**
-     * It shows the SwipeRefreshLayout progress
-     */
-    public void showSwipeProgress() {
-        mRefreshLayout.setRefreshing(true);
-    }
-    /**
-     * It shows the SwipeRefreshLayout progress
+     * Disables swipe gesture.
+     *
+     * Sets the 'enabled' state of the refresh layouts contained in the fragment.
+     *
+     * When 'false' is set, prevents user gestures but keeps the option to refresh programatically,
+     *
+     * @param   enabled     Desired state for capturing swipe gesture.
      */
-    public void hideSwipeProgress() {
-        mRefreshLayout.setRefreshing(false);
+    public void setSwipeEnabled(boolean enabled) {
+        mRefreshListLayout.setEnabled(enabled);
+        mRefreshGridLayout.setEnabled(enabled);
+        mRefreshEmptyLayout.setEnabled(enabled);
     }
 
     /**
@@ -307,11 +339,71 @@ implements OnItemClickListener, OnEnforceableRefreshListener {
 
     @Override
     public void onRefresh(boolean ignoreETag) {
-        mRefreshLayout.setRefreshing(false);
+        mRefreshListLayout.setRefreshing(false);
+        mRefreshGridLayout.setRefreshing(false);
         mRefreshEmptyLayout.setRefreshing(false);
 
         if (mOnRefreshListener != null) {
             mOnRefreshListener.onRefresh(ignoreETag);
         }
     }
+
+
+    protected void setChoiceMode(int choiceMode) {
+        mListView.setChoiceMode(choiceMode);
+        mGridView.setChoiceMode(choiceMode);
+    }
+
+    protected void registerForContextMenu() {
+        registerForContextMenu(mListView);
+        registerForContextMenu(mGridView);
+        mListView.setOnCreateContextMenuListener(this);
+        mGridView.setOnCreateContextMenuListener(this);
+    }
+
+    /**
+     * TODO doc
+     * To be called before setAdapter, or GridViewWithHeaderAndFooter will throw an exception
+     *
+     * @param enabled
+     */
+    protected void setFooterEnabled(boolean enabled) {
+        if (enabled) {
+            if (mGridView.getFooterViewCount() == 0) {
+                if (mGridFooterView.getParent() != null ) {
+                    ((ViewGroup) mGridFooterView.getParent()).removeView(mGridFooterView);
+                }
+                mGridView.addFooterView(mGridFooterView, null, false);
+            }
+            mGridFooterView.invalidate();
+
+            if (mListView.getFooterViewsCount() == 0) {
+                if (mListFooterView.getParent() != null ) {
+                    ((ViewGroup) mListFooterView.getParent()).removeView(mListFooterView);
+                }
+                mListView.addFooterView(mListFooterView, null, false);
+            }
+            mListFooterView.invalidate();
+
+        } else {
+            mGridView.removeFooterView(mGridFooterView);
+            mListView.removeFooterView(mListFooterView);
+        }
+    }
+
+    /**
+     * TODO doc
+     * @param text
+     */
+    protected void setFooterText(String text) {
+        if (text != null && text.length() > 0) {
+            ((TextView)mListFooterView.findViewById(R.id.footerText)).setText(text);
+            ((TextView)mGridFooterView.findViewById(R.id.footerText)).setText(text);
+            setFooterEnabled(true);
+
+        } else {
+            setFooterEnabled(false);
+        }
+    }
+
 }
index 30ac7e1..6a19957 100644 (file)
@@ -1,6 +1,10 @@
-/* ownCloud Android client application
+/**
+ *   ownCloud Android client application
+ *
+ *   @author Bartek Przybylski
+ *   @author David A. Velasco
  *   Copyright (C) 2011  Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
+ *   Copyright (C) 2015 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,
@@ -52,9 +56,6 @@ import com.owncloud.android.utils.DisplayUtils;
 
 /**
  * This Fragment is used to display the details about a file.
- * 
- * @author Bartek Przybylski
- * @author David A. Velasco
  */
 public class FileDetailFragment extends FileFragment implements OnClickListener {
 
@@ -536,9 +537,7 @@ public class FileDetailFragment extends FileFragment implements OnClickListener
 
     
     /**
-     * Helper class responsible for updating the progress bar shown for file uploading or downloading  
-     * 
-     * @author David A. Velasco
+     * Helper class responsible for updating the progress bar shown for file uploading or downloading
      */
     private class ProgressListener implements OnDatatransferProgressListener {
         int mLastPercent = 0;
index 3e6fa31..87dca25 100644 (file)
@@ -1,5 +1,8 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2013  ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
+ *   Copyright (C) 2015  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,
@@ -30,9 +33,6 @@ import com.owncloud.android.ui.activity.ComponentsGetter;
 
 /**
  * Common methods for {@link Fragment}s containing {@link OCFile}s
- * 
- * @author David A. Velasco
- *
  */
 public class FileFragment extends SherlockFragment {
     
@@ -102,8 +102,6 @@ public class FileFragment extends SherlockFragment {
     /**
      * Interface to implement by any Activity that includes some instance of FileListFragment
      * Interface to implement by any Activity that includes some instance of FileFragment
-     * 
-     * @author David A. Velasco
      */
     public interface ContainerActivity extends ComponentsGetter {
 
index c9408b1..b3e40d8 100644 (file)
@@ -1,6 +1,9 @@
-/* ownCloud Android client application
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
  *   Copyright (C) 2011  Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
+ *   Copyright (C) 2015 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,
@@ -38,9 +41,6 @@ import com.owncloud.android.ui.adapter.LocalFileListAdapter;
 
 /**
  * A Fragment that lists all files and folders in a given LOCAL path.
- * 
- * @author David A. Velasco
- * 
  */
 public class LocalFileListFragment extends ExtendedListFragment {
     private static final String TAG = "LocalFileListFragment";
@@ -76,12 +76,12 @@ public class LocalFileListFragment extends ExtendedListFragment {
     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
         Log_OC.i(TAG, "onCreateView() start");
         View v = super.onCreateView(inflater, container, savedInstanceState);
-        getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
-        disableSwipe(); // Disable pull refresh
+        setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
+        setSwipeEnabled(false); // Disable pull-to-refresh
         setMessageForEmptyList(getString(R.string.local_file_list_empty));
         Log_OC.i(TAG, "onCreateView() end");
         return v;
-    }    
+    }
 
 
     /**
@@ -98,7 +98,6 @@ public class LocalFileListFragment extends ExtendedListFragment {
         Log_OC.i(TAG, "onActivityCreated() stop");
     }
     
-    
     /**
      * Checks the file clicked over. Browses inside if it is a directory. Notifies the container activity in any case.
      */
@@ -195,10 +194,10 @@ public class LocalFileListFragment extends ExtendedListFragment {
             directory = directory.getParentFile();
         }
 
-        mList.clearChoices();   // by now, only files in the same directory will be kept as selected
+        mCurrentListView.clearChoices();   // by now, only files in the same directory will be kept as selected
         mAdapter.swapDirectory(directory);
         if (mDirectory == null || !mDirectory.equals(directory)) {
-            mList.setSelectionFromTop(0, 0);
+            mCurrentListView.setSelection(0);
         }
         mDirectory = directory;
     }
@@ -211,11 +210,11 @@ public class LocalFileListFragment extends ExtendedListFragment {
      */
     public String[] getCheckedFilePaths() {
         ArrayList<String> result = new ArrayList<String>();
-        SparseBooleanArray positions = mList.getCheckedItemPositions();
+        SparseBooleanArray positions = mCurrentListView.getCheckedItemPositions();
         if (positions.size() > 0) {
             for (int i = 0; i < positions.size(); i++) {
                 if (positions.get(positions.keyAt(i)) == true) {
-                    result.add(((File) mList.getItemAtPosition(positions.keyAt(i))).getAbsolutePath());
+                    result.add(((File) mCurrentListView.getItemAtPosition(positions.keyAt(i))).getAbsolutePath());
                 }
             }
 
@@ -227,15 +226,13 @@ public class LocalFileListFragment extends ExtendedListFragment {
     
     /**
      * Interface to implement by any Activity that includes some instance of LocalFileListFragment
-     * 
-     * @author David A. Velasco
      */
     public interface ContainerActivity {
 
         /**
          * Callback method invoked when a directory is clicked by the user on the files list
          *  
-         * @param file
+         * @param directory
          */
         public void onDirectoryClick(File directory);
         
index b70262f..60ac78d 100644 (file)
@@ -1,6 +1,11 @@
-/* ownCloud Android client application
+/**
+ *   ownCloud Android client application
+ *
+ *   @author Bartek Przybylski
+ *   @author masensio
+ *   @author David A. Velasco
  *   Copyright (C) 2011  Bartek Przybylski
- *   Copyright (C) 2012-2014 ownCloud Inc.
+ *   Copyright (C) 2015 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,
 package com.owncloud.android.ui.fragment;
 
 import java.io.File;
-import java.util.Vector;
 
 import android.app.Activity;
-import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
 import android.support.v4.widget.SwipeRefreshLayout;
@@ -31,8 +34,6 @@ import android.view.MenuItem;
 import android.view.View;
 import android.widget.AdapterView;
 import android.widget.AdapterView.AdapterContextMenuInfo;
-import android.widget.TextView;
-import android.view.LayoutInflater;
 
 import com.owncloud.android.R;
 import com.owncloud.android.datamodel.FileDataStorageManager;
@@ -54,10 +55,6 @@ import com.owncloud.android.utils.FileStorageUtils;
  * A Fragment that lists all files and folders in a given path.
  * 
  * TODO refactorize to get rid of direct dependency on FileDisplayActivity
- * 
- * @author Bartek Przybylski
- * @author masensio
- * @author David A. Velasco
  */
 public class OCFileListFragment extends ExtendedListFragment {
     
@@ -71,11 +68,13 @@ public class OCFileListFragment extends ExtendedListFragment {
             
     private static final String KEY_FILE = MY_PACKAGE + ".extra.FILE";
 
+    private final static Double THUMBNAIL_THRESHOLD = 0.5;
+
     private FileFragment.ContainerActivity mContainerActivity;
    
     private OCFile mFile = null;
     private FileListListAdapter mAdapter;
-    private View mFooterView;
+    private boolean mJustFolders;
     
     private OCFile mTargetFile;
 
@@ -123,22 +122,23 @@ public class OCFileListFragment extends ExtendedListFragment {
             mFile = savedInstanceState.getParcelable(KEY_FILE);
         }
 
-        mFooterView = ((LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(
-                        R.layout.list_footer, null, false);
-        setFooterView(mFooterView);
+        if (mJustFolders) {
+            setFooterEnabled(false);
+        } else {
+            setFooterEnabled(true);
+        }
 
         Bundle args = getArguments();
-        boolean justFolders = (args == null) ? false : args.getBoolean(ARG_JUST_FOLDERS, false); 
+        mJustFolders = (args == null) ? false : args.getBoolean(ARG_JUST_FOLDERS, false);
         mAdapter = new FileListListAdapter(
-                justFolders,
+                mJustFolders,
                 getSherlockActivity(),
                 mContainerActivity
                 );
         setListAdapter(mAdapter);
 
-        registerForContextMenu(getListView());
-        getListView().setOnCreateContextMenuListener(this);
-    }
+        registerForContextMenu();
+  }
 
     /**
      * Saves the current listed folder.
@@ -389,54 +389,65 @@ public class OCFileListFragment extends ExtendedListFragment {
 
             mAdapter.swapDirectory(directory, storageManager);
             if (mFile == null || !mFile.equals(directory)) {
-                mList.setSelectionFromTop(0, 0);
+                mCurrentListView.setSelection(0);
             }
             mFile = directory;
-            
-            // Update Footer
-            TextView footerText = (TextView) mFooterView.findViewById(R.id.footerText);
-            Log_OC.d("footer", String.valueOf(System.currentTimeMillis()));
-            footerText.setText(generateFooterText(directory));
-            Log_OC.d("footer", String.valueOf(System.currentTimeMillis()));
+
+            updateLayout();
+
         }
     }
-    
-    private String generateFooterText(OCFile directory) {
-        Integer files = 0;
-        Integer folders = 0;
 
-        FileDataStorageManager storageManager = mContainerActivity.getStorageManager();
-        Vector<OCFile> mFiles = storageManager.getFolderContent(mFile);
+    private void updateLayout() {
+        if (!mJustFolders) {
+            int filesCount = 0, foldersCount = 0, imagesCount = 0;
+            int count = mAdapter.getCount();
+            OCFile file;
+            for (int i=0; i < count ; i++) {
+                file = (OCFile) mAdapter.getItem(i);
+                if (file.isFolder()) {
+                    foldersCount++;
+                } else {
+                    filesCount++;
+                    if (file.isImage()){
+                        imagesCount++;
+                    }
+                }
+            }
+            // set footer text
+            setFooterText(generateFooterText(filesCount, foldersCount));
 
-        for (OCFile ocFile : mFiles) {
-            if (ocFile.isFolder()) {
-                folders++;
+            // decide grid vs list view
+            if (((double)imagesCount / (double)filesCount) >= THUMBNAIL_THRESHOLD) {
+                switchToGridView();
             } else {
-                files++;
+                switchToListView();
             }
         }
+    }
 
+    private String generateFooterText(int filesCount, int foldersCount) {
         String output = "";
-       
-        if (files > 0){
-            if (files == 1) {
-                output = output + files.toString() + " " + getResources().getString(R.string.file_list_file);
+        if (filesCount > 0){
+            if (filesCount == 1) {
+                output = output + filesCount + " " + getResources().getString(R.string.file_list_file);
             } else {
-                output = output + files.toString() + " " + getResources().getString(R.string.file_list_files);
+                output = output + filesCount + " " + getResources().getString(R.string.file_list_files);
             }
         }
-        if (folders > 0 && files > 0){
+        if (foldersCount > 0 && filesCount > 0){
             output = output + ", ";
         }
-        if (folders == 1) {
-            output = output + folders.toString() + " " + getResources().getString(R.string.file_list_folder);
-        } else if (folders > 1) {
-            output = output + folders.toString() + " " + getResources().getString(R.string.file_list_folders);
+        if (foldersCount == 1) {
+            output = output + foldersCount + " " + getResources().getString(R.string.file_list_folder);
+        } else if (foldersCount > 1) {
+            output = output + foldersCount + " " + getResources().getString(R.string.file_list_folders);
         }
-        
+
         return output;
     }
-    
+
+
     public void sortByName(boolean descending) {
         mAdapter.setSortOrder(FileStorageUtils.SORT_NAME, descending);
     }
index 7af29c6..99a4d44 100644 (file)
@@ -1,6 +1,8 @@
-/* ownCloud Android client application
- * 
- *   Copyright (C) 2012-2013  ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
+ *   Copyright (C) 2015  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,
@@ -42,8 +44,6 @@ import com.owncloud.android.lib.common.utils.Log_OC;
 
 /**
  * This Fragment is used to monitor the progress of a file downloading.
- * 
- * @author David A. Velasco
  */
 public class FileDownloadFragment extends FileFragment implements OnClickListener {
 
@@ -308,9 +308,7 @@ public class FileDownloadFragment extends FileFragment implements OnClickListene
 
     
     /**
-     * Helper class responsible for updating the progress bar shown for file uploading or downloading  
-     * 
-     * @author David A. Velasco
+     * Helper class responsible for updating the progress bar shown for file uploading or downloading
      */
     private class ProgressListener implements OnDatatransferProgressListener {
         int mLastPercent = 0;
index 213aee0..1f6ab80 100644 (file)
@@ -1,5 +1,8 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2013  ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
+ *   Copyright (C) 2015  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,
@@ -62,8 +65,6 @@ import com.owncloud.android.utils.DisplayUtils;
 
 /**
  *  Holds a swiping galley where image files contained in an ownCloud directory are shown
- *  
- *  @author David A. Velasco
  */
 public class PreviewImageActivity extends FileActivity implements 
  FileFragment.ContainerActivity,
index 0995793..9d1cd60 100644 (file)
@@ -1,5 +1,8 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2014 ownCloud Inc. 
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
+ *   Copyright (C) 2015 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,
@@ -54,8 +57,8 @@ import com.owncloud.android.ui.dialog.ConfirmationDialogFragment;
 import com.owncloud.android.ui.dialog.RemoveFileDialogFragment;
 import com.owncloud.android.ui.fragment.FileFragment;
 import com.owncloud.android.utils.BitmapUtils;
-import com.owncloud.android.utils.TouchImageViewCustom;
 
+import third_parties.michaelOrtiz.TouchImageViewCustom;
 
 
 /**
@@ -64,8 +67,6 @@ import com.owncloud.android.utils.TouchImageViewCustom;
  * Trying to get an instance with NULL {@link OCFile} or ownCloud {@link Account} values will produce an {@link IllegalStateException}.
  * 
  * If the {@link OCFile} passed is not downloaded, an {@link IllegalStateException} is generated on instantiation too.
- * 
- * @author David A. Velasco
  */
 public class PreviewImageFragment extends FileFragment {
 
index 3c15de7..14ae34f 100644 (file)
@@ -1,5 +1,8 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2013  ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
+ *   Copyright (C) 2015  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,
@@ -38,9 +41,7 @@ import com.owncloud.android.ui.fragment.FileFragment;
 import com.owncloud.android.utils.FileStorageUtils;
 
 /**
- * Adapter class that provides Fragment instances  
- * 
- * @author David A. Velasco
+ * Adapter class that provides Fragment instances
  */
 //public class PreviewImagePagerAdapter extends PagerAdapter {
 public class PreviewImagePagerAdapter extends FragmentStatePagerAdapter {
index 7d6489b..d82faa5 100644 (file)
@@ -1,5 +1,8 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2013 ownCloud Inc. 
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
+ *   Copyright (C) 2015 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,
@@ -64,8 +67,6 @@ import com.owncloud.android.ui.fragment.FileFragment;
  * Trying to get an instance with NULL {@link OCFile} or ownCloud {@link Account} values will produce an {@link IllegalStateException}.
  * 
  * By now, if the {@link OCFile} passed is not downloaded, an {@link IllegalStateException} is generated on instantiation too.
- * 
- * @author David A. Velasco
  */
 public class PreviewMediaFragment extends FileFragment implements
         OnTouchListener {
index 39e8e23..938d52d 100644 (file)
@@ -1,5 +1,8 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2013 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
+ *   Copyright (C) 2015 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,
@@ -45,9 +48,7 @@ import com.owncloud.android.lib.common.utils.Log_OC;
  *  Used as an utility to preview video files contained in an ownCloud account.
  *  
  *  Currently, it always plays in landscape mode, full screen. When the playback ends,
- *  the activity is finished. 
- *  
- *  @author David A. Velasco
+ *  the activity is finished.
  */
 public class PreviewVideoActivity extends FileActivity implements OnCompletionListener, OnPreparedListener, OnErrorListener {
 
index 92824f4..ce7590d 100644 (file)
@@ -1,5 +1,8 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2014 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
+ *   Copyright (C) 2015 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,
@@ -30,8 +33,6 @@ import java.io.File;
 
 /**
  * Utility class with methods for decoding Bitmaps.
- * 
- * @author David A. Velasco
  */
 public class BitmapUtils {
     
index 32d9017..905f60b 100644 (file)
@@ -1,6 +1,10 @@
-/* ownCloud Android client application\r
+/**\r
+ *   ownCloud Android client application\r
+ *\r
+ *   @author Bartek Przybylski\r
+ *   @author David A. Velasco\r
  *   Copyright (C) 2011  Bartek Przybylski\r
- *   Copyright (C) 2012-2013 ownCloud Inc.\r
+ *   Copyright (C) 2015 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
@@ -26,6 +30,7 @@ import java.util.Date;
 import java.util.HashMap;\r
 import java.util.HashSet;\r
 import java.util.Set;\r
+import java.util.Vector;\r
 \r
 import android.annotation.TargetApi;\r
 import android.content.Context;\r
@@ -39,9 +44,6 @@ import com.owncloud.android.datamodel.OCFile;
 \r
 /**\r
  * A helper class for some string operations.\r
- * \r
- * @author Bartek Przybylski\r
- * @author David A. Velasco\r
  */\r
 public class DisplayUtils {\r
     \r
@@ -228,7 +230,7 @@ public class DisplayUtils {
     \r
     /**\r
      * Converts Unix time to human readable format\r
-     * @param miliseconds that have passed since 01/01/1970\r
+     * @param milliseconds that have passed since 01/01/1970\r
      * @return The human readable time for the users locale\r
      */\r
     public static String unixTimeToHumanReadable(long milliseconds) {\r
@@ -340,4 +342,5 @@ public class DisplayUtils {
         }\r
         return path;\r
     }\r
+\r
 }\r
index 9f13804..12a1a5a 100644 (file)
@@ -1,4 +1,7 @@
-/* ownCloud Android client application
+/**
+ *   ownCloud Android client application
+ *
+ *   @author masensio
  *   Copyright (C) 2014 ownCloud Inc.
  *
  *   This program is free software: you can redistribute it and/or modify
@@ -41,10 +44,8 @@ import com.owncloud.android.operations.UnshareLinkOperation;
 import com.owncloud.android.operations.UploadFileOperation;
 
 /**
- * Class to choose proper error messages to show to the user depending on the results of operations, always following the same policy
- * 
- * @author masensio
- *
+ * Class to choose proper error messages to show to the user depending on the results of operations,
+ * always following the same policy
  */
 
 public class ErrorMessageAdapter {
index b462cd9..e70302f 100644 (file)
@@ -1,5 +1,8 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2013 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
+ *   Copyright (C) 2015 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,
@@ -36,12 +39,11 @@ import android.preference.PreferenceManager;
 import android.net.Uri;
 import android.os.Environment;
 import android.os.StatFs;
+import android.webkit.MimeTypeMap;
 
 
 /**
  * Static methods to help in access to local file system.
- * 
- * @author David A. Velasco
  */
 public class FileStorageUtils {
     public static Integer mSortOrder;
@@ -135,7 +137,7 @@ public class FileStorageUtils {
     /**
      * Creates and populates a new {@link RemoteFile} object with the data read from an {@link OCFile}.
      * 
-     * @param oCFile    OCFile 
+     * @param ocFile    OCFile
      * @return          New RemoteFile instance representing the resource described by ocFile.
      */
     public static RemoteFile fillRemoteFile(OCFile ocFile){
@@ -171,7 +173,7 @@ public class FileStorageUtils {
     
     /**
      * Sorts list by Date
-     * @param sortAscending true: ascending, false: descending
+     * @param files
      */
     public static Vector<OCFile> sortByDate(Vector<OCFile> files){
         final Integer val;
@@ -239,7 +241,7 @@ public class FileStorageUtils {
 
     /**
      * Sorts list by Name
-     * @param sortAscending true: ascending, false: descending
+     * @param files     files to sort
      */
     public static Vector<OCFile> sortByName(Vector<OCFile> files){
         final Integer val;
@@ -284,6 +286,21 @@ public class FileStorageUtils {
             return result;
         }
         return 0;
-    } 
+    }
+
+    /**
+     * Mimetype String of a file
+     * @param path
+     * @return
+     */
+    public static String getMimeTypeFromName(String path) {
+        String extension = "";
+        int pos = path.lastIndexOf('.');
+        if (pos >= 0) {
+            extension = path.substring(pos + 1);
+        }
+        String result = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension.toLowerCase());
+        return (result != null) ? result : "";
+    }
   
 }
index 13ead88..6292a2b 100644 (file)
@@ -1,6 +1,9 @@
-/* ownCloud Android client application\r
+/**\r
+ *   ownCloud Android client application\r
+ *\r
+ *   @author Bartek Przybylski\r
  *   Copyright (C) 2011  Bartek Przybylski\r
- *   Copyright (C) 2012-2013 ownCloud Inc.\r
+ *   Copyright (C) 2015 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
@@ -19,9 +22,6 @@ package com.owncloud.android.utils;
 \r
 /**\r
  * Represents a session to an ownCloud instance\r
- * \r
- * @author Bartek Przybylski\r
- * \r
  */\r
 public class OwnCloudSession {\r
     private String mSessionName;\r
index be44f8f..4a70631 100644 (file)
@@ -1,6 +1,8 @@
-/* ownCloud Android client application
+/**
+ *   ownCloud Android client application
+ *
  *   Copyright (C) 2012 Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
+ *   Copyright (C) 2015 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,
diff --git a/src/com/owncloud/android/utils/TouchImageViewCustom.java b/src/com/owncloud/android/utils/TouchImageViewCustom.java
deleted file mode 100644 (file)
index a0f7b79..0000000
+++ /dev/null
@@ -1,1276 +0,0 @@
-/*
- * TouchImageView.java
- * By: Michael Ortiz
- * Updated By: Patrick Lackemacher
- * Updated By: Babay88
- * Updated By: @ipsilondev
- * Updated By: hank-cp
- * Updated By: singpolyma
- * -------------------
- * Extends Android ImageView to include pinch zooming, panning, fling and double tap zoom.
- */
-
-package com.owncloud.android.utils;
-
-import com.owncloud.android.ui.preview.ImageViewCustom;
-
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Matrix;
-import android.graphics.PointF;
-import android.graphics.RectF;
-import android.graphics.drawable.Drawable;
-import android.net.Uri;
-import android.os.Build;
-import android.os.Build.VERSION;
-import android.os.Build.VERSION_CODES;
-import android.os.Bundle;
-import android.os.Parcelable;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.GestureDetector;
-import android.view.MotionEvent;
-import android.view.ScaleGestureDetector;
-import android.view.View;
-import android.view.animation.AccelerateDecelerateInterpolator;
-import android.widget.OverScroller;
-import android.widget.Scroller;
-
-public class TouchImageViewCustom extends ImageViewCustom {
-    private static final String DEBUG = "DEBUG";
-       
-       //
-       // SuperMin and SuperMax multipliers. Determine how much the image can be
-       // zoomed below or above the zoom boundaries, before animating back to the
-       // min/max zoom boundary.
-       //
-       private static final float SUPER_MIN_MULTIPLIER = .75f;
-       private static final float SUPER_MAX_MULTIPLIER = 1.25f;
-
-    //
-    // Scale of image ranges from minScale to maxScale, where minScale == 1
-    // when the image is stretched to fit view.
-    //
-    private float normalizedScale;
-    
-    //
-    // Matrix applied to image. MSCALE_X and MSCALE_Y should always be equal.
-    // MTRANS_X and MTRANS_Y are the other values used. prevMatrix is the matrix
-    // saved prior to the screen rotating.
-    //
-       private Matrix matrix, prevMatrix;
-
-    private static enum State { NONE, DRAG, ZOOM, FLING, ANIMATE_ZOOM };
-    private State state;
-
-    private float minScale;
-    private float maxScale;
-    private float superMinScale;
-    private float superMaxScale;
-    private float[] m;
-    
-    private Context context;
-    private Fling fling;
-    
-    private ScaleType mScaleType;
-    
-    private boolean imageRenderedAtLeastOnce;
-    private boolean onDrawReady;
-    
-    private ZoomVariables delayedZoomVariables;
-
-    //
-    // Size of view and previous view size (ie before rotation)
-    //
-    private int viewWidth, viewHeight, prevViewWidth, prevViewHeight;
-    
-    //
-    // Size of image when it is stretched to fit view. Before and After rotation.
-    //
-    private float matchViewWidth, matchViewHeight, prevMatchViewWidth, prevMatchViewHeight;
-    
-    private ScaleGestureDetector mScaleDetector;
-    private GestureDetector mGestureDetector;
-    private GestureDetector.OnDoubleTapListener doubleTapListener = null;
-    private OnTouchListener userTouchListener = null;
-    private OnTouchImageViewListener touchImageViewListener = null;
-
-    public TouchImageViewCustom(Context context) {
-        super(context);
-        sharedConstructing(context);
-    }
-
-    public TouchImageViewCustom(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        sharedConstructing(context);
-    }
-    
-    public TouchImageViewCustom(Context context, AttributeSet attrs, int defStyle) {
-       super(context, attrs, defStyle);
-       sharedConstructing(context);
-    }
-    
-    private void sharedConstructing(Context context) {
-        super.setClickable(true);
-        this.context = context;
-        mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
-        mGestureDetector = new GestureDetector(context, new GestureListener());
-        matrix = new Matrix();
-        prevMatrix = new Matrix();
-        m = new float[9];
-        normalizedScale = 1;
-        if (mScaleType == null) {
-               mScaleType = ScaleType.FIT_CENTER;
-        }
-        minScale = 1;
-        maxScale = 3;
-        superMinScale = SUPER_MIN_MULTIPLIER * minScale;
-        superMaxScale = SUPER_MAX_MULTIPLIER * maxScale;
-        setImageMatrix(matrix);
-        setScaleType(ScaleType.MATRIX);
-        setState(State.NONE);
-        onDrawReady = false;
-        super.setOnTouchListener(new PrivateOnTouchListener());
-    }
-
-    @Override
-    public void setOnTouchListener(View.OnTouchListener l) {
-        userTouchListener = l;
-    }
-    
-    public void setOnTouchImageViewListener(OnTouchImageViewListener l) {
-       touchImageViewListener = l;
-    }
-
-    public void setOnDoubleTapListener(GestureDetector.OnDoubleTapListener l) {
-        doubleTapListener = l;
-    }
-
-    @Override
-    public void setImageResource(int resId) {
-       super.setImageResource(resId);
-       savePreviousImageValues();
-       fitImageToView();
-    }
-    
-    @Override
-    public void setImageBitmap(Bitmap bm) {
-       super.setImageBitmap(bm);
-       savePreviousImageValues();
-       fitImageToView();
-    }
-    
-    @Override
-    public void setImageDrawable(Drawable drawable) {
-       super.setImageDrawable(drawable);
-       savePreviousImageValues();
-       fitImageToView();
-    }
-    
-    @Override
-    public void setImageURI(Uri uri) {
-       super.setImageURI(uri);
-       savePreviousImageValues();
-       fitImageToView();
-    }
-    
-    @Override
-    public void setScaleType(ScaleType type) {
-       if (type == ScaleType.FIT_START || type == ScaleType.FIT_END) {
-               throw new UnsupportedOperationException("TouchImageView does not support FIT_START or FIT_END");
-       }
-       if (type == ScaleType.MATRIX) {
-               super.setScaleType(ScaleType.MATRIX);
-               
-       } else {
-               mScaleType = type;
-               if (onDrawReady) {
-                       //
-                       // If the image is already rendered, scaleType has been called programmatically
-                       // and the TouchImageView should be updated with the new scaleType.
-                       //
-                       setZoom(this);
-               }
-       }
-    }
-    
-    @Override
-    public ScaleType getScaleType() {
-       return mScaleType;
-    }
-    
-    /**
-     * Returns false if image is in initial, unzoomed state. False, otherwise.
-     * @return true if image is zoomed
-     */
-    public boolean isZoomed() {
-       return normalizedScale != 1;
-    }
-    
-    /**
-     * Return a Rect representing the zoomed image.
-     * @return rect representing zoomed image
-     */
-    public RectF getZoomedRect() {
-       if (mScaleType == ScaleType.FIT_XY) {
-               throw new UnsupportedOperationException("getZoomedRect() not supported with FIT_XY");
-       }
-       PointF topLeft = transformCoordTouchToBitmap(0, 0, true);
-       PointF bottomRight = transformCoordTouchToBitmap(viewWidth, viewHeight, true);
-       
-       float w = getDrawable().getIntrinsicWidth();
-       float h = getDrawable().getIntrinsicHeight();
-       return new RectF(topLeft.x / w, topLeft.y / h, bottomRight.x / w, bottomRight.y / h);
-    }
-    
-    /**
-     * Save the current matrix and view dimensions
-     * in the prevMatrix and prevView variables.
-     */
-    private void savePreviousImageValues() {
-       if (matrix != null && viewHeight != 0 && viewWidth != 0) {
-               matrix.getValues(m);
-               prevMatrix.setValues(m);
-               prevMatchViewHeight = matchViewHeight;
-               prevMatchViewWidth = matchViewWidth;
-               prevViewHeight = viewHeight;
-               prevViewWidth = viewWidth;
-       }
-    }
-    
-    @Override
-    public Parcelable onSaveInstanceState() {
-       Bundle bundle = new Bundle();
-       bundle.putParcelable("instanceState", super.onSaveInstanceState());
-       bundle.putFloat("saveScale", normalizedScale);
-       bundle.putFloat("matchViewHeight", matchViewHeight);
-       bundle.putFloat("matchViewWidth", matchViewWidth);
-       bundle.putInt("viewWidth", viewWidth);
-       bundle.putInt("viewHeight", viewHeight);
-       matrix.getValues(m);
-       bundle.putFloatArray("matrix", m);
-       bundle.putBoolean("imageRendered", imageRenderedAtLeastOnce);
-       return bundle;
-    }
-    
-    @Override
-    public void onRestoreInstanceState(Parcelable state) {
-       if (state instanceof Bundle) {
-               Bundle bundle = (Bundle) state;
-               normalizedScale = bundle.getFloat("saveScale");
-               m = bundle.getFloatArray("matrix");
-               prevMatrix.setValues(m);
-               prevMatchViewHeight = bundle.getFloat("matchViewHeight");
-               prevMatchViewWidth = bundle.getFloat("matchViewWidth");
-               prevViewHeight = bundle.getInt("viewHeight");
-               prevViewWidth = bundle.getInt("viewWidth");
-               imageRenderedAtLeastOnce = bundle.getBoolean("imageRendered");
-               super.onRestoreInstanceState(bundle.getParcelable("instanceState"));
-               return;
-       }
-
-       super.onRestoreInstanceState(state);
-    }
-    
-    @Override
-    protected void onDraw(Canvas canvas) {
-       onDrawReady = true;
-       imageRenderedAtLeastOnce = true;
-       if (delayedZoomVariables != null) {
-               setZoom(delayedZoomVariables.scale, delayedZoomVariables.focusX, delayedZoomVariables.focusY, delayedZoomVariables.scaleType);
-               delayedZoomVariables = null;
-       }
-       super.onDraw(canvas);
-    }
-    
-    @Override
-    public void onConfigurationChanged(Configuration newConfig) {
-       super.onConfigurationChanged(newConfig);
-       savePreviousImageValues();
-    }
-    
-    /**
-     * Get the max zoom multiplier.
-     * @return max zoom multiplier.
-     */
-    public float getMaxZoom() {
-       return maxScale;
-    }
-
-    /**
-     * Set the max zoom multiplier. Default value: 3.
-     * @param max max zoom multiplier.
-     */
-    public void setMaxZoom(float max) {
-        maxScale = max;
-        superMaxScale = SUPER_MAX_MULTIPLIER * maxScale;
-    }
-    
-    /**
-     * Get the min zoom multiplier.
-     * @return min zoom multiplier.
-     */
-    public float getMinZoom() {
-       return minScale;
-    }
-    
-    /**
-     * Get the current zoom. This is the zoom relative to the initial
-     * scale, not the original resource.
-     * @return current zoom multiplier.
-     */
-    public float getCurrentZoom() {
-       return normalizedScale;
-    }
-    
-    /**
-     * Set the min zoom multiplier. Default value: 1.
-     * @param min min zoom multiplier.
-     */
-    public void setMinZoom(float min) {
-       minScale = min;
-       superMinScale = SUPER_MIN_MULTIPLIER * minScale;
-    }
-    
-    /**
-     * Reset zoom and translation to initial state.
-     */
-    public void resetZoom() {
-       normalizedScale = 1;
-       fitImageToView();
-    }
-    
-    /**
-     * Set zoom to the specified scale. Image will be centered by default.
-     * @param scale
-     */
-    public void setZoom(float scale) {
-       setZoom(scale, 0.5f, 0.5f);
-    }
-    
-    /**
-     * Set zoom to the specified scale. Image will be centered around the point
-     * (focusX, focusY). These floats range from 0 to 1 and denote the focus point
-     * as a fraction from the left and top of the view. For example, the top left 
-     * corner of the image would be (0, 0). And the bottom right corner would be (1, 1).
-     * @param scale
-     * @param focusX
-     * @param focusY
-     */
-    public void setZoom(float scale, float focusX, float focusY) {
-       setZoom(scale, focusX, focusY, mScaleType);
-    }
-    
-    /**
-     * Set zoom to the specified scale. Image will be centered around the point
-     * (focusX, focusY). These floats range from 0 to 1 and denote the focus point
-     * as a fraction from the left and top of the view. For example, the top left 
-     * corner of the image would be (0, 0). And the bottom right corner would be (1, 1).
-     * @param scale
-     * @param focusX
-     * @param focusY
-     * @param scaleType
-     */
-    public void setZoom(float scale, float focusX, float focusY, ScaleType scaleType) {
-       //
-       // setZoom can be called before the image is on the screen, but at this point, 
-       // image and view sizes have not yet been calculated in onMeasure. Thus, we should
-       // delay calling setZoom until the view has been measured.
-       //
-       if (!onDrawReady) {
-               delayedZoomVariables = new ZoomVariables(scale, focusX, focusY, scaleType);
-               return;
-       }
-       
-       if (scaleType != mScaleType) {
-               setScaleType(scaleType);
-       }
-       resetZoom();
-       scaleImage(scale, viewWidth / 2, viewHeight / 2, true);
-       matrix.getValues(m);
-       m[Matrix.MTRANS_X] = -((focusX * getImageWidth()) - (viewWidth * 0.5f));
-       m[Matrix.MTRANS_Y] = -((focusY * getImageHeight()) - (viewHeight * 0.5f));
-       matrix.setValues(m);
-       fixTrans();
-       setImageMatrix(matrix);
-    }
-    
-    /**
-     * Set zoom parameters equal to another TouchImageView. Including scale, position,
-     * and ScaleType.
-     * @param TouchImageView
-     */
-    public void setZoom(TouchImageViewCustom img) {
-       PointF center = img.getScrollPosition();
-       setZoom(img.getCurrentZoom(), center.x, center.y, img.getScaleType());
-    }
-    
-    /**
-     * Return the point at the center of the zoomed image. The PointF coordinates range
-     * in value between 0 and 1 and the focus point is denoted as a fraction from the left 
-     * and top of the view. For example, the top left corner of the image would be (0, 0). 
-     * And the bottom right corner would be (1, 1).
-     * @return PointF representing the scroll position of the zoomed image.
-     */
-    public PointF getScrollPosition() {
-       Drawable drawable = getDrawable();
-       if (drawable == null) {
-               return null;
-       }
-       int drawableWidth = drawable.getIntrinsicWidth();
-        int drawableHeight = drawable.getIntrinsicHeight();
-        
-        PointF point = transformCoordTouchToBitmap(viewWidth / 2, viewHeight / 2, true);
-        point.x /= drawableWidth;
-        point.y /= drawableHeight;
-        return point;
-    }
-    
-    /**
-     * Set the focus point of the zoomed image. The focus points are denoted as a fraction from the
-     * left and top of the view. The focus points can range in value between 0 and 1. 
-     * @param focusX
-     * @param focusY
-     */
-    public void setScrollPosition(float focusX, float focusY) {
-       setZoom(normalizedScale, focusX, focusY);
-    }
-    
-    /**
-     * Performs boundary checking and fixes the image matrix if it 
-     * is out of bounds.
-     */
-    private void fixTrans() {
-        matrix.getValues(m);
-        float transX = m[Matrix.MTRANS_X];
-        float transY = m[Matrix.MTRANS_Y];
-        
-        float fixTransX = getFixTrans(transX, viewWidth, getImageWidth());
-        float fixTransY = getFixTrans(transY, viewHeight, getImageHeight());
-        
-        if (fixTransX != 0 || fixTransY != 0) {
-            matrix.postTranslate(fixTransX, fixTransY);
-        }
-    }
-    
-    /**
-     * When transitioning from zooming from focus to zoom from center (or vice versa)
-     * the image can become unaligned within the view. This is apparent when zooming
-     * quickly. When the content size is less than the view size, the content will often
-     * be centered incorrectly within the view. fixScaleTrans first calls fixTrans() and 
-     * then makes sure the image is centered correctly within the view.
-     */
-    private void fixScaleTrans() {
-       fixTrans();
-       matrix.getValues(m);
-       if (getImageWidth() < viewWidth) {
-               m[Matrix.MTRANS_X] = (viewWidth - getImageWidth()) / 2;
-       }
-       
-       if (getImageHeight() < viewHeight) {
-               m[Matrix.MTRANS_Y] = (viewHeight - getImageHeight()) / 2;
-       }
-       matrix.setValues(m);
-    }
-
-    private float getFixTrans(float trans, float viewSize, float contentSize) {
-        float minTrans, maxTrans;
-
-        if (contentSize <= viewSize) {
-            minTrans = 0;
-            maxTrans = viewSize - contentSize;
-            
-        } else {
-            minTrans = viewSize - contentSize;
-            maxTrans = 0;
-        }
-
-        if (trans < minTrans)
-            return -trans + minTrans;
-        if (trans > maxTrans)
-            return -trans + maxTrans;
-        return 0;
-    }
-    
-    private float getFixDragTrans(float delta, float viewSize, float contentSize) {
-        if (contentSize <= viewSize) {
-            return 0;
-        }
-        return delta;
-    }
-    
-    private float getImageWidth() {
-       return matchViewWidth * normalizedScale;
-    }
-    
-    private float getImageHeight() {
-       return matchViewHeight * normalizedScale;
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        Drawable drawable = getDrawable();
-        if (drawable == null || drawable.getIntrinsicWidth() == 0 || drawable.getIntrinsicHeight() == 0) {
-               setMeasuredDimension(0, 0);
-               return;
-        }
-        
-        int drawableWidth = drawable.getIntrinsicWidth();
-        int drawableHeight = drawable.getIntrinsicHeight();
-        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
-        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
-        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
-        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
-        viewWidth = setViewSize(widthMode, widthSize, drawableWidth);
-        viewHeight = setViewSize(heightMode, heightSize, drawableHeight);
-        
-        //
-        // Set view dimensions
-        //
-        setMeasuredDimension(viewWidth, viewHeight);
-        
-        //
-        // Fit content within view
-        //
-        fitImageToView();
-    }
-    
-    /**
-     * If the normalizedScale is equal to 1, then the image is made to fit the screen. Otherwise,
-     * it is made to fit the screen according to the dimensions of the previous image matrix. This
-     * allows the image to maintain its zoom after rotation.
-     */
-    private void fitImageToView() {
-       Drawable drawable = getDrawable();
-        if (drawable == null || drawable.getIntrinsicWidth() == 0 || drawable.getIntrinsicHeight() == 0) {
-               return;
-        }
-        if (matrix == null || prevMatrix == null) {
-               return;
-        }
-        
-        int drawableWidth = drawable.getIntrinsicWidth();
-        int drawableHeight = drawable.getIntrinsicHeight();
-       
-       //
-       // Scale image for view
-       //
-        float scaleX = (float) viewWidth / drawableWidth;
-        float scaleY = (float) viewHeight / drawableHeight;
-        
-        switch (mScaleType) {
-        case CENTER:
-               scaleX = scaleY = 1;
-               break;
-               
-        case CENTER_CROP:
-               scaleX = scaleY = Math.max(scaleX, scaleY);
-               break;
-               
-        case CENTER_INSIDE:
-               scaleX = scaleY = Math.min(1, Math.min(scaleX, scaleY));
-               
-        case FIT_CENTER:
-               scaleX = scaleY = Math.min(scaleX, scaleY);
-               break;
-               
-        case FIT_XY:
-               break;
-               
-       default:
-               //
-               // FIT_START and FIT_END not supported
-               //
-               throw new UnsupportedOperationException("TouchImageView does not support FIT_START or FIT_END");
-               
-        }
-
-        //
-        // Center the image
-        //
-        float redundantXSpace = viewWidth - (scaleX * drawableWidth);
-        float redundantYSpace = viewHeight - (scaleY * drawableHeight);
-        matchViewWidth = viewWidth - redundantXSpace;
-        matchViewHeight = viewHeight - redundantYSpace;
-        if (!isZoomed() && !imageRenderedAtLeastOnce) {
-               //
-               // Stretch and center image to fit view
-               //
-               matrix.setScale(scaleX, scaleY);
-               matrix.postTranslate(redundantXSpace / 2, redundantYSpace / 2);
-               normalizedScale = 1;
-               
-        } else {
-               //
-               // These values should never be 0 or we will set viewWidth and viewHeight
-               // to NaN in translateMatrixAfterRotate. To avoid this, call savePreviousImageValues
-               // to set them equal to the current values.
-               //
-               if (prevMatchViewWidth == 0 || prevMatchViewHeight == 0) {
-                       savePreviousImageValues();
-               }
-               
-               prevMatrix.getValues(m);
-               
-               //
-               // Rescale Matrix after rotation
-               //
-               m[Matrix.MSCALE_X] = matchViewWidth / drawableWidth * normalizedScale;
-               m[Matrix.MSCALE_Y] = matchViewHeight / drawableHeight * normalizedScale;
-               
-               //
-               // TransX and TransY from previous matrix
-               //
-            float transX = m[Matrix.MTRANS_X];
-            float transY = m[Matrix.MTRANS_Y];
-            
-            //
-            // Width
-            //
-            float prevActualWidth = prevMatchViewWidth * normalizedScale;
-            float actualWidth = getImageWidth();
-            translateMatrixAfterRotate(Matrix.MTRANS_X, transX, prevActualWidth, actualWidth, prevViewWidth, viewWidth, drawableWidth);
-            
-            //
-            // Height
-            //
-            float prevActualHeight = prevMatchViewHeight * normalizedScale;
-            float actualHeight = getImageHeight();
-            translateMatrixAfterRotate(Matrix.MTRANS_Y, transY, prevActualHeight, actualHeight, prevViewHeight, viewHeight, drawableHeight);
-            
-            //
-            // Set the matrix to the adjusted scale and translate values.
-            //
-            matrix.setValues(m);
-        }
-        fixTrans();
-        setImageMatrix(matrix);
-    }
-    
-    /**
-     * Set view dimensions based on layout params
-     * 
-     * @param mode 
-     * @param size
-     * @param drawableWidth
-     * @return
-     */
-    private int setViewSize(int mode, int size, int drawableWidth) {
-       int viewSize;
-       switch (mode) {
-               case MeasureSpec.EXACTLY:
-                       viewSize = size;
-                       break;
-                       
-               case MeasureSpec.AT_MOST:
-                       viewSize = Math.min(drawableWidth, size);
-                       break;
-                       
-               case MeasureSpec.UNSPECIFIED:
-                       viewSize = drawableWidth;
-                       break;
-                       
-               default:
-                       viewSize = size;
-                       break;
-               }
-       return viewSize;
-    }
-    
-    /**
-     * After rotating, the matrix needs to be translated. This function finds the area of image 
-     * which was previously centered and adjusts translations so that is again the center, post-rotation.
-     * 
-     * @param axis Matrix.MTRANS_X or Matrix.MTRANS_Y
-     * @param trans the value of trans in that axis before the rotation
-     * @param prevImageSize the width/height of the image before the rotation
-     * @param imageSize width/height of the image after rotation
-     * @param prevViewSize width/height of view before rotation
-     * @param viewSize width/height of view after rotation
-     * @param drawableSize width/height of drawable
-     */
-    private void translateMatrixAfterRotate(int axis, float trans, float prevImageSize, float imageSize, int prevViewSize, int viewSize, int drawableSize) {
-       if (imageSize < viewSize) {
-               //
-               // The width/height of image is less than the view's width/height. Center it.
-               //
-               m[axis] = (viewSize - (drawableSize * m[Matrix.MSCALE_X])) * 0.5f;
-               
-        } else if (trans > 0) {
-               //
-               // The image is larger than the view, but was not before rotation. Center it.
-               //
-               m[axis] = -((imageSize - viewSize) * 0.5f);
-               
-        } else {
-               //
-               // Find the area of the image which was previously centered in the view. Determine its distance
-               // from the left/top side of the view as a fraction of the entire image's width/height. Use that percentage
-               // to calculate the trans in the new view width/height.
-               //
-               float percentage = (Math.abs(trans) + (0.5f * prevViewSize)) / prevImageSize;
-               m[axis] = -((percentage * imageSize) - (viewSize * 0.5f));
-        }
-    }
-    
-    private void setState(State state) {
-       this.state = state;
-    }
-    
-    public boolean canScrollHorizontallyFroyo(int direction) {
-        return canScrollHorizontally(direction);
-    }
-    
-    @Override
-    public boolean canScrollHorizontally(int direction) {
-       matrix.getValues(m);
-       float x = m[Matrix.MTRANS_X];
-       
-       if (getImageWidth() < viewWidth) {
-               return false;
-               
-       } else if (x >= -1 && direction < 0) {
-               return false;
-               
-       } else if (Math.abs(x) + viewWidth + 1 >= getImageWidth() && direction > 0) {
-               return false;
-       }
-       
-       return true;
-    }
-    
-    /**
-     * Gesture Listener detects a single click or long click and passes that on
-     * to the view's listener.
-     * @author Ortiz
-     *
-     */
-    private class GestureListener extends GestureDetector.SimpleOnGestureListener {
-       
-        @Override
-        public boolean onSingleTapConfirmed(MotionEvent e)
-        {
-            if(doubleTapListener != null) {
-               return doubleTapListener.onSingleTapConfirmed(e);
-            }
-               return performClick();
-        }
-        
-        @Override
-        public void onLongPress(MotionEvent e)
-        {
-               performLongClick();
-        }
-        
-        @Override
-        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)
-        {
-               if (fling != null) {
-                       //
-                       // If a previous fling is still active, it should be cancelled so that two flings
-                       // are not run simultaenously.
-                       //
-                       fling.cancelFling();
-               }
-               fling = new Fling((int) velocityX, (int) velocityY);
-               compatPostOnAnimation(fling);
-               return super.onFling(e1, e2, velocityX, velocityY);
-        }
-        
-        @Override
-        public boolean onDoubleTap(MotionEvent e) {
-               boolean consumed = false;
-            if(doubleTapListener != null) {
-               consumed = doubleTapListener.onDoubleTap(e);
-            }
-               if (state == State.NONE) {
-                       float targetZoom = (normalizedScale == minScale) ? maxScale : minScale;
-                       DoubleTapZoom doubleTap = new DoubleTapZoom(targetZoom, e.getX(), e.getY(), false);
-                       compatPostOnAnimation(doubleTap);
-                       consumed = true;
-               }
-               return consumed;
-        }
-
-        @Override
-        public boolean onDoubleTapEvent(MotionEvent e) {
-            if(doubleTapListener != null) {
-               return doubleTapListener.onDoubleTapEvent(e);
-            }
-            return false;
-        }
-    }
-    
-    public interface OnTouchImageViewListener {
-       public void onMove();
-    }
-    
-    /**
-     * Responsible for all touch events. Handles the heavy lifting of drag and also sends
-     * touch events to Scale Detector and Gesture Detector.
-     * @author Ortiz
-     *
-     */
-    private class PrivateOnTouchListener implements OnTouchListener {
-       
-       //
-        // Remember last point position for dragging
-        //
-        private PointF last = new PointF();
-       
-       @Override
-        public boolean onTouch(View v, MotionEvent event) {
-            mScaleDetector.onTouchEvent(event);
-            mGestureDetector.onTouchEvent(event);
-            PointF curr = new PointF(event.getX(), event.getY());
-            
-            if (state == State.NONE || state == State.DRAG || state == State.FLING) {
-                   switch (event.getAction()) {
-                       case MotionEvent.ACTION_DOWN:
-                               last.set(curr);
-                           if (fling != null)
-                               fling.cancelFling();
-                           setState(State.DRAG);
-                           break;
-                           
-                       case MotionEvent.ACTION_MOVE:
-                           if (state == State.DRAG) {
-                               float deltaX = curr.x - last.x;
-                               float deltaY = curr.y - last.y;
-                               float fixTransX = getFixDragTrans(deltaX, viewWidth, getImageWidth());
-                               float fixTransY = getFixDragTrans(deltaY, viewHeight, getImageHeight());
-                               matrix.postTranslate(fixTransX, fixTransY);
-                               fixTrans();
-                               last.set(curr.x, curr.y);
-                           }
-                           break;
-       
-                       case MotionEvent.ACTION_UP:
-                       case MotionEvent.ACTION_POINTER_UP:
-                           setState(State.NONE);
-                           break;
-                   }
-            }
-            
-            setImageMatrix(matrix);
-            
-            //
-               // User-defined OnTouchListener
-               //
-               if(userTouchListener != null) {
-                       userTouchListener.onTouch(v, event);
-               }
-            
-               //
-               // OnTouchImageViewListener is set: TouchImageView dragged by user.
-               //
-               if (touchImageViewListener != null) {
-                       touchImageViewListener.onMove();
-               }
-               
-            //
-            // indicate event was handled
-            //
-            return true;
-        }
-    }
-
-    /**
-     * ScaleListener detects user two finger scaling and scales image.
-     * @author Ortiz
-     *
-     */
-    private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
-        @Override
-        public boolean onScaleBegin(ScaleGestureDetector detector) {
-            setState(State.ZOOM);
-            return true;
-        }
-
-        @Override
-        public boolean onScale(ScaleGestureDetector detector) {
-               scaleImage(detector.getScaleFactor(), detector.getFocusX(), detector.getFocusY(), true);
-               
-               //
-               // OnTouchImageViewListener is set: TouchImageView pinch zoomed by user.
-               //
-               if (touchImageViewListener != null) {
-                       touchImageViewListener.onMove();
-               }
-            return true;
-        }
-        
-        @Override
-        public void onScaleEnd(ScaleGestureDetector detector) {
-               super.onScaleEnd(detector);
-               setState(State.NONE);
-               boolean animateToZoomBoundary = false;
-               float targetZoom = normalizedScale;
-               if (normalizedScale > maxScale) {
-                       targetZoom = maxScale;
-                       animateToZoomBoundary = true;
-                       
-               } else if (normalizedScale < minScale) {
-                       targetZoom = minScale;
-                       animateToZoomBoundary = true;
-               }
-               
-               if (animateToZoomBoundary) {
-                       DoubleTapZoom doubleTap = new DoubleTapZoom(targetZoom, viewWidth / 2, viewHeight / 2, true);
-                       compatPostOnAnimation(doubleTap);
-               }
-        }
-    }
-    
-    private void scaleImage(double deltaScale, float focusX, float focusY, boolean stretchImageToSuper) {
-       
-       float lowerScale, upperScale;
-       if (stretchImageToSuper) {
-               lowerScale = superMinScale;
-               upperScale = superMaxScale;
-               
-       } else {
-               lowerScale = minScale;
-               upperScale = maxScale;
-       }
-       
-       float origScale = normalizedScale;
-        normalizedScale *= deltaScale;
-        if (normalizedScale > upperScale) {
-            normalizedScale = upperScale;
-            deltaScale = upperScale / origScale;
-        } else if (normalizedScale < lowerScale) {
-            normalizedScale = lowerScale;
-            deltaScale = lowerScale / origScale;
-        }
-        
-        matrix.postScale((float) deltaScale, (float) deltaScale, focusX, focusY);
-        fixScaleTrans();
-    }
-    
-    /**
-     * DoubleTapZoom calls a series of runnables which apply
-     * an animated zoom in/out graphic to the image.
-     * @author Ortiz
-     *
-     */
-    private class DoubleTapZoom implements Runnable {
-       
-       private long startTime;
-       private static final float ZOOM_TIME = 500;
-       private float startZoom, targetZoom;
-       private float bitmapX, bitmapY;
-       private boolean stretchImageToSuper;
-       private AccelerateDecelerateInterpolator interpolator = new AccelerateDecelerateInterpolator();
-       private PointF startTouch;
-       private PointF endTouch;
-
-       DoubleTapZoom(float targetZoom, float focusX, float focusY, boolean stretchImageToSuper) {
-               setState(State.ANIMATE_ZOOM);
-               startTime = System.currentTimeMillis();
-               this.startZoom = normalizedScale;
-               this.targetZoom = targetZoom;
-               this.stretchImageToSuper = stretchImageToSuper;
-               PointF bitmapPoint = transformCoordTouchToBitmap(focusX, focusY, false);
-               this.bitmapX = bitmapPoint.x;
-               this.bitmapY = bitmapPoint.y;
-               
-               //
-               // Used for translating image during scaling
-               //
-               startTouch = transformCoordBitmapToTouch(bitmapX, bitmapY);
-               endTouch = new PointF(viewWidth / 2, viewHeight / 2);
-       }
-
-               @Override
-               public void run() {
-                       float t = interpolate();
-                       double deltaScale = calculateDeltaScale(t);
-                       scaleImage(deltaScale, bitmapX, bitmapY, stretchImageToSuper);
-                       translateImageToCenterTouchPosition(t);
-                       fixScaleTrans();
-                       setImageMatrix(matrix);
-                       
-                       //
-                       // OnTouchImageViewListener is set: double tap runnable updates listener
-                       // with every frame.
-                       //
-                       if (touchImageViewListener != null) {
-                               touchImageViewListener.onMove();
-                       }
-                       
-                       if (t < 1f) {
-                               //
-                               // We haven't finished zooming
-                               //
-                               compatPostOnAnimation(this);
-                               
-                       } else {
-                               //
-                               // Finished zooming
-                               //
-                               setState(State.NONE);
-                       }
-               }
-               
-               /**
-                * Interpolate between where the image should start and end in order to translate
-                * the image so that the point that is touched is what ends up centered at the end
-                * of the zoom.
-                * @param t
-                */
-               private void translateImageToCenterTouchPosition(float t) {
-                       float targetX = startTouch.x + t * (endTouch.x - startTouch.x);
-                       float targetY = startTouch.y + t * (endTouch.y - startTouch.y);
-                       PointF curr = transformCoordBitmapToTouch(bitmapX, bitmapY);
-                       matrix.postTranslate(targetX - curr.x, targetY - curr.y);
-               }
-               
-               /**
-                * Use interpolator to get t
-                * @return
-                */
-               private float interpolate() {
-                       long currTime = System.currentTimeMillis();
-                       float elapsed = (currTime - startTime) / ZOOM_TIME;
-                       elapsed = Math.min(1f, elapsed);
-                       return interpolator.getInterpolation(elapsed);
-               }
-               
-               /**
-                * Interpolate the current targeted zoom and get the delta
-                * from the current zoom.
-                * @param t
-                * @return
-                */
-               private double calculateDeltaScale(float t) {
-                       double zoom = startZoom + t * (targetZoom - startZoom);
-                       return zoom / normalizedScale;
-               }
-    }
-    
-    /**
-     * This function will transform the coordinates in the touch event to the coordinate 
-     * system of the drawable that the imageview contain
-     * @param x x-coordinate of touch event
-     * @param y y-coordinate of touch event
-     * @param clipToBitmap Touch event may occur within view, but outside image content. True, to clip return value
-     *                         to the bounds of the bitmap size.
-     * @return Coordinates of the point touched, in the coordinate system of the original drawable.
-     */
-    private PointF transformCoordTouchToBitmap(float x, float y, boolean clipToBitmap) {
-         matrix.getValues(m);
-         float origW = getDrawable().getIntrinsicWidth();
-         float origH = getDrawable().getIntrinsicHeight();
-         float transX = m[Matrix.MTRANS_X];
-         float transY = m[Matrix.MTRANS_Y];
-         float finalX = ((x - transX) * origW) / getImageWidth();
-         float finalY = ((y - transY) * origH) / getImageHeight();
-         
-         if (clipToBitmap) {
-                finalX = Math.min(Math.max(finalX, 0), origW);
-                finalY = Math.min(Math.max(finalY, 0), origH);
-         }
-         
-         return new PointF(finalX , finalY);
-    }
-    
-    /**
-     * Inverse of transformCoordTouchToBitmap. This function will transform the coordinates in the
-     * drawable's coordinate system to the view's coordinate system.
-     * @param bx x-coordinate in original bitmap coordinate system
-     * @param by y-coordinate in original bitmap coordinate system
-     * @return Coordinates of the point in the view's coordinate system.
-     */
-    private PointF transformCoordBitmapToTouch(float bx, float by) {
-        matrix.getValues(m);        
-        float origW = getDrawable().getIntrinsicWidth();
-        float origH = getDrawable().getIntrinsicHeight();
-        float px = bx / origW;
-        float py = by / origH;
-        float finalX = m[Matrix.MTRANS_X] + getImageWidth() * px;
-        float finalY = m[Matrix.MTRANS_Y] + getImageHeight() * py;
-        return new PointF(finalX , finalY);
-    }
-    
-    /**
-     * Fling launches sequential runnables which apply
-     * the fling graphic to the image. The values for the translation
-     * are interpolated by the Scroller.
-     * @author Ortiz
-     *
-     */
-    private class Fling implements Runnable {
-       
-        CompatScroller scroller;
-       int currX, currY;
-       
-       Fling(int velocityX, int velocityY) {
-               setState(State.FLING);
-               scroller = new CompatScroller(context);
-               matrix.getValues(m);
-               
-               int startX = (int) m[Matrix.MTRANS_X];
-               int startY = (int) m[Matrix.MTRANS_Y];
-               int minX, maxX, minY, maxY;
-               
-               if (getImageWidth() > viewWidth) {
-                       minX = viewWidth - (int) getImageWidth();
-                       maxX = 0;
-                       
-               } else {
-                       minX = maxX = startX;
-               }
-               
-               if (getImageHeight() > viewHeight) {
-                       minY = viewHeight - (int) getImageHeight();
-                       maxY = 0;
-                       
-               } else {
-                       minY = maxY = startY;
-               }
-               
-               scroller.fling(startX, startY, (int) velocityX, (int) velocityY, minX,
-                    maxX, minY, maxY);
-               currX = startX;
-               currY = startY;
-       }
-       
-       public void cancelFling() {
-               if (scroller != null) {
-                       setState(State.NONE);
-                       scroller.forceFinished(true);
-               }
-       }
-       
-               @Override
-               public void run() {
-                       
-                       //
-                       // OnTouchImageViewListener is set: TouchImageView listener has been flung by user.
-                       // Listener runnable updated with each frame of fling animation.
-                       //
-                       if (touchImageViewListener != null) {
-                               touchImageViewListener.onMove();
-                       }
-                       
-                       if (scroller.isFinished()) {
-                       scroller = null;
-                       return;
-               }
-                       
-                       if (scroller.computeScrollOffset()) {
-                       int newX = scroller.getCurrX();
-                   int newY = scroller.getCurrY();
-                   int transX = newX - currX;
-                   int transY = newY - currY;
-                   currX = newX;
-                   currY = newY;
-                   matrix.postTranslate(transX, transY);
-                   fixTrans();
-                   setImageMatrix(matrix);
-                   compatPostOnAnimation(this);
-               }
-               }
-    }
-    
-    @TargetApi(Build.VERSION_CODES.GINGERBREAD)
-       private class CompatScroller {
-       Scroller scroller;
-       OverScroller overScroller;
-       boolean isPreGingerbread;
-       
-       public CompatScroller(Context context) {
-               if (VERSION.SDK_INT < VERSION_CODES.GINGERBREAD) {
-                       isPreGingerbread = true;
-                       scroller = new Scroller(context);
-                       
-               } else {
-                       isPreGingerbread = false;
-                       overScroller = new OverScroller(context);
-               }
-       }
-       
-       public void fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, int maxY) {
-               if (isPreGingerbread) {
-                       scroller.fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY);
-               } else {
-                       overScroller.fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY);
-               }
-       }
-       
-       public void forceFinished(boolean finished) {
-               if (isPreGingerbread) {
-                       scroller.forceFinished(finished);
-               } else {
-                       overScroller.forceFinished(finished);
-               }
-       }
-       
-       public boolean isFinished() {
-               if (isPreGingerbread) {
-                       return scroller.isFinished();
-               } else {
-                       return overScroller.isFinished();
-               }
-       }
-       
-       public boolean computeScrollOffset() {
-               if (isPreGingerbread) {
-                       return scroller.computeScrollOffset();
-               } else {
-                       overScroller.computeScrollOffset();
-                       return overScroller.computeScrollOffset();
-               }
-       }
-       
-       public int getCurrX() {
-               if (isPreGingerbread) {
-                       return scroller.getCurrX();
-               } else {
-                       return overScroller.getCurrX();
-               }
-       }
-       
-       public int getCurrY() {
-               if (isPreGingerbread) {
-                       return scroller.getCurrY();
-               } else {
-                       return overScroller.getCurrY();
-               }
-       }
-    }
-    
-    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
-       private void compatPostOnAnimation(Runnable runnable) {
-       if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {
-            postOnAnimation(runnable);
-            
-        } else {
-            postDelayed(runnable, 1000/60);
-        }
-    }
-    
-    private class ZoomVariables {
-       public float scale;
-       public float focusX;
-       public float focusY;
-       public ScaleType scaleType;
-       
-       public ZoomVariables(float scale, float focusX, float focusY, ScaleType scaleType) {
-               this.scale = scale;
-               this.focusX = focusX;
-               this.focusY = focusY;
-               this.scaleType = scaleType;
-       }
-    }
-    
-    private void printMatrixInfo() {
-       float[] n = new float[9];
-       matrix.getValues(n);
-       Log.d(DEBUG, "Scale: " + n[Matrix.MSCALE_X] + " TransX: " + n[Matrix.MTRANS_X] + " TransY: " + n[Matrix.MTRANS_Y]);
-    }
-}
\ No newline at end of file
index e66d2c9..8070e36 100644 (file)
@@ -1,5 +1,7 @@
-/* ownCloud Android client application
- *   Copyright (C) 2012-2014 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   Copyright (C) 2015 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,
index 1077d15..cb0dac4 100644 (file)
@@ -1,6 +1,8 @@
-/* ownCloud Android client application
+/**
+ *   ownCloud Android client application
+ *
  *   Copyright (C) 2012 Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
+ *   Copyright (C) 2015 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,
diff --git a/src/third_parties/in/srain/cube/GridViewWithHeaderAndFooter.java b/src/third_parties/in/srain/cube/GridViewWithHeaderAndFooter.java
new file mode 100644 (file)
index 0000000..508380a
--- /dev/null
@@ -0,0 +1,841 @@
+
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package third_parties.in.srain.cube;
+
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.database.DataSetObservable;
+import android.database.DataSetObserver;
+import android.os.Build;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.Filter;
+import android.widget.Filterable;
+import android.widget.FrameLayout;
+import android.widget.GridView;
+import android.widget.ListAdapter;
+import android.widget.WrapperListAdapter;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+
+/**
+ * A {@link android.widget.GridView} that supports adding header rows in a
+ * very similar way to {@link android.widget.ListView}.
+ * See {@link GridViewWithHeaderAndFooter#addHeaderView(View, Object, boolean)}
+ * See {@link GridViewWithHeaderAndFooter#addFooterView(View, Object, boolean)}
+ */
+public class GridViewWithHeaderAndFooter extends GridView {
+
+    public static boolean DEBUG = false;
+
+    /**
+     * A class that represents a fixed view in a list, for example a header at the top
+     * or a footer at the bottom.
+     */
+    private static class FixedViewInfo {
+        /**
+         * The view to add to the grid
+         */
+        public View view;
+        public ViewGroup viewContainer;
+        /**
+         * The data backing the view. This is returned from {@link android.widget.ListAdapter#getItem(int)}.
+         */
+        public Object data;
+        /**
+         * <code>true</code> if the fixed view should be selectable in the grid
+         */
+        public boolean isSelectable;
+    }
+
+    private int mNumColumns = AUTO_FIT;
+    private View mViewForMeasureRowHeight = null;
+    private int mRowHeight = -1;
+    private static final String LOG_TAG = "grid-view-with-header-and-footer";
+
+    private ArrayList<FixedViewInfo> mHeaderViewInfos = new ArrayList<FixedViewInfo>();
+    private ArrayList<FixedViewInfo> mFooterViewInfos = new ArrayList<FixedViewInfo>();
+
+    private void initHeaderGridView() {
+    }
+
+    public GridViewWithHeaderAndFooter(Context context) {
+        super(context);
+        initHeaderGridView();
+    }
+
+    public GridViewWithHeaderAndFooter(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        initHeaderGridView();
+    }
+
+    public GridViewWithHeaderAndFooter(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        initHeaderGridView();
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        ListAdapter adapter = getAdapter();
+        if (adapter != null && adapter instanceof HeaderViewGridAdapter) {
+            ((HeaderViewGridAdapter) adapter).setNumColumns(getNumColumnsCompatible());
+            ((HeaderViewGridAdapter) adapter).setRowHeight(getRowHeight());
+        }
+    }
+
+    @Override
+    public void setClipChildren(boolean clipChildren) {
+        // Ignore, since the header rows depend on not being clipped
+    }
+
+    /**
+     * Do not call this method unless you know how it works.
+     *
+     * @param clipChildren
+     */
+    public void setClipChildrenSupper(boolean clipChildren) {
+        super.setClipChildren(false);
+    }
+
+    /**
+     * Add a fixed view to appear at the top of the grid. If addHeaderView is
+     * called more than once, the views will appear in the order they were
+     * added. Views added using this call can take focus if they want.
+     * <p/>
+     * NOTE: Call this before calling setAdapter. This is so HeaderGridView can wrap
+     * the supplied cursor with one that will also account for header views.
+     *
+     * @param v The view to add.
+     */
+    public void addHeaderView(View v) {
+        addHeaderView(v, null, true);
+    }
+
+    /**
+     * Add a fixed view to appear at the top of the grid. If addHeaderView is
+     * called more than once, the views will appear in the order they were
+     * added. Views added using this call can take focus if they want.
+     * <p/>
+     * NOTE: Call this before calling setAdapter. This is so HeaderGridView can wrap
+     * the supplied cursor with one that will also account for header views.
+     *
+     * @param v            The view to add.
+     * @param data         Data to associate with this view
+     * @param isSelectable whether the item is selectable
+     */
+    public void addHeaderView(View v, Object data, boolean isSelectable) {
+        ListAdapter adapter = getAdapter();
+        if (adapter != null && !(adapter instanceof HeaderViewGridAdapter)) {
+            throw new IllegalStateException(
+                    "Cannot add header view to grid -- setAdapter has already been called.");
+        }
+
+        ViewGroup.LayoutParams lyp = v.getLayoutParams();
+
+        FixedViewInfo info = new FixedViewInfo();
+        FrameLayout fl = new FullWidthFixedViewLayout(getContext());
+
+        if (lyp != null) {
+            v.setLayoutParams(new FrameLayout.LayoutParams(lyp.width, lyp.height));
+            fl.setLayoutParams(new LayoutParams(lyp.width, lyp.height));
+        }
+        fl.addView(v);
+        info.view = v;
+        info.viewContainer = fl;
+        info.data = data;
+        info.isSelectable = isSelectable;
+        mHeaderViewInfos.add(info);
+        // in the case of re-adding a header view, or adding one later on,
+        // we need to notify the observer
+        if (adapter != null) {
+            ((HeaderViewGridAdapter) adapter).notifyDataSetChanged();
+        }
+    }
+
+    public void addFooterView(View v) {
+        addFooterView(v, null, true);
+    }
+
+    public void addFooterView(View v, Object data, boolean isSelectable) {
+        ListAdapter mAdapter = getAdapter();
+        if (mAdapter != null && !(mAdapter instanceof HeaderViewGridAdapter)) {
+            throw new IllegalStateException(
+                    "Cannot add header view to grid -- setAdapter has already been called.");
+        }
+
+        ViewGroup.LayoutParams lyp = v.getLayoutParams();
+
+        FixedViewInfo info = new FixedViewInfo();
+        FrameLayout fl = new FullWidthFixedViewLayout(getContext());
+
+        if (lyp != null) {
+            v.setLayoutParams(new FrameLayout.LayoutParams(lyp.width, lyp.height));
+            fl.setLayoutParams(new LayoutParams(lyp.width, lyp.height));
+        }
+        fl.addView(v);
+        info.view = v;
+        info.viewContainer = fl;
+        info.data = data;
+        info.isSelectable = isSelectable;
+        mFooterViewInfos.add(info);
+
+        if (mAdapter != null) {
+            ((HeaderViewGridAdapter) mAdapter).notifyDataSetChanged();
+        }
+    }
+
+    public int getHeaderViewCount() {
+        return mHeaderViewInfos.size();
+    }
+
+    public int getFooterViewCount() {
+        return mFooterViewInfos.size();
+    }
+
+    /**
+     * Removes a previously-added header view.
+     *
+     * @param v The view to remove
+     * @return true if the view was removed, false if the view was not a header
+     * view
+     */
+    public boolean removeHeaderView(View v) {
+        if (mHeaderViewInfos.size() > 0) {
+            boolean result = false;
+            ListAdapter adapter = getAdapter();
+            if (adapter != null && ((HeaderViewGridAdapter) adapter).removeHeader(v)) {
+                result = true;
+            }
+            removeFixedViewInfo(v, mHeaderViewInfos);
+            return result;
+        }
+        return false;
+    }
+
+    /**
+     * Removes a previously-added footer view.
+     *
+     * @param v The view to remove
+     * @return true if the view was removed, false if the view was not a header
+     * view
+     */
+    public boolean removeFooterView(View v) {
+        if (mFooterViewInfos.size() > 0) {
+            boolean result = false;
+            ListAdapter adapter = getAdapter();
+            if (adapter != null && ((HeaderViewGridAdapter) adapter).removeFooter(v)) {
+                result = true;
+            }
+            removeFixedViewInfo(v, mFooterViewInfos);
+            return result;
+        }
+        return false;
+    }
+
+    private void removeFixedViewInfo(View v, ArrayList<FixedViewInfo> where) {
+        int len = where.size();
+        for (int i = 0; i < len; ++i) {
+            FixedViewInfo info = where.get(i);
+            if (info.view == v) {
+                where.remove(i);
+                break;
+            }
+        }
+    }
+
+    @TargetApi(11)
+    private int getNumColumnsCompatible() {
+        if (Build.VERSION.SDK_INT >= 11) {
+            return super.getNumColumns();
+        } else {
+            try {
+                Field numColumns = getClass().getSuperclass().getDeclaredField("mNumColumns");
+                numColumns.setAccessible(true);
+                return numColumns.getInt(this);
+            } catch (Exception e) {
+                if (mNumColumns != -1) {
+                    return mNumColumns;
+                }
+                throw new RuntimeException("Can not determine the mNumColumns for this API platform, please call setNumColumns to set it.");
+            }
+        }
+    }
+
+    @TargetApi(16)
+    private int getColumnWidthCompatible() {
+        if (Build.VERSION.SDK_INT >= 16) {
+            return super.getColumnWidth();
+        } else {
+            try {
+                Field numColumns = getClass().getSuperclass().getDeclaredField("mColumnWidth");
+                numColumns.setAccessible(true);
+                return numColumns.getInt(this);
+            } catch (NoSuchFieldException e) {
+                throw new RuntimeException(e);
+            } catch (IllegalAccessException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        mViewForMeasureRowHeight = null;
+    }
+
+    public void invalidateRowHeight() {
+        mRowHeight = -1;
+    }
+
+    public int getRowHeight() {
+        if (mRowHeight > 0) {
+            return mRowHeight;
+        }
+        ListAdapter adapter = getAdapter();
+        int numColumns = getNumColumnsCompatible();
+
+        // adapter has not been set or has no views in it;
+        if (adapter == null || adapter.getCount() <= numColumns * (mHeaderViewInfos.size() + mFooterViewInfos.size())) {
+            return -1;
+        }
+        int mColumnWidth = getColumnWidthCompatible();
+        View view = getAdapter().getView(numColumns * mHeaderViewInfos.size(), mViewForMeasureRowHeight, this);
+        LayoutParams p = (LayoutParams) view.getLayoutParams();
+        if (p == null) {
+            p = new LayoutParams(-1, -2, 0);
+            view.setLayoutParams(p);
+        }
+        int childHeightSpec = getChildMeasureSpec(
+                MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 0, p.height);
+        int childWidthSpec = getChildMeasureSpec(
+                MeasureSpec.makeMeasureSpec(mColumnWidth, MeasureSpec.EXACTLY), 0, p.width);
+        view.measure(childWidthSpec, childHeightSpec);
+        mViewForMeasureRowHeight = view;
+        mRowHeight = view.getMeasuredHeight();
+        return mRowHeight;
+    }
+
+    @TargetApi(11)
+    public void tryToScrollToBottomSmoothly() {
+        int lastPos = getAdapter().getCount() - 1;
+        if (Build.VERSION.SDK_INT >= 11) {
+            smoothScrollToPositionFromTop(lastPos, 0);
+        } else {
+            setSelection(lastPos);
+        }
+    }
+
+    @TargetApi(11)
+    public void tryToScrollToBottomSmoothly(int duration) {
+        int lastPos = getAdapter().getCount() - 1;
+        if (Build.VERSION.SDK_INT >= 11) {
+            smoothScrollToPositionFromTop(lastPos, 0, duration);
+        } else {
+            setSelection(lastPos);
+        }
+    }
+
+    @Override
+    public void setAdapter(ListAdapter adapter) {
+        if (mHeaderViewInfos.size() > 0 || mFooterViewInfos.size() > 0) {
+            HeaderViewGridAdapter headerViewGridAdapter = new HeaderViewGridAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);
+            int numColumns = getNumColumnsCompatible();
+            if (numColumns > 1) {
+                headerViewGridAdapter.setNumColumns(numColumns);
+            }
+            headerViewGridAdapter.setRowHeight(getRowHeight());
+            super.setAdapter(headerViewGridAdapter);
+        } else {
+            super.setAdapter(adapter);
+        }
+    }
+
+    /**
+     * full width
+     */
+    private class FullWidthFixedViewLayout extends FrameLayout {
+
+        public FullWidthFixedViewLayout(Context context) {
+            super(context);
+        }
+
+        @Override
+        protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+            int realLeft = GridViewWithHeaderAndFooter.this.getPaddingLeft() + getPaddingLeft();
+            // Try to make where it should be, from left, full width
+            if (realLeft != left) {
+                offsetLeftAndRight(realLeft - left);
+            }
+            super.onLayout(changed, left, top, right, bottom);
+        }
+
+        @Override
+        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+            int targetWidth = GridViewWithHeaderAndFooter.this.getMeasuredWidth()
+                    - GridViewWithHeaderAndFooter.this.getPaddingLeft()
+                    - GridViewWithHeaderAndFooter.this.getPaddingRight();
+            widthMeasureSpec = MeasureSpec.makeMeasureSpec(targetWidth,
+                    MeasureSpec.getMode(widthMeasureSpec));
+            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        }
+    }
+
+    @Override
+    public void setNumColumns(int numColumns) {
+        super.setNumColumns(numColumns);
+        mNumColumns = numColumns;
+        ListAdapter adapter = getAdapter();
+        if (adapter != null && adapter instanceof HeaderViewGridAdapter) {
+            ((HeaderViewGridAdapter) adapter).setNumColumns(numColumns);
+        }
+    }
+
+    /**
+     * ListAdapter used when a HeaderGridView has header views. This ListAdapter
+     * wraps another one and also keeps track of the header views and their
+     * associated data objects.
+     * <p>This is intended as a base class; you will probably not need to
+     * use this class directly in your own code.
+     */
+    private static class HeaderViewGridAdapter implements WrapperListAdapter, Filterable {
+        // This is used to notify the container of updates relating to number of columns
+        // or headers changing, which changes the number of placeholders needed
+        private final DataSetObservable mDataSetObservable = new DataSetObservable();
+        private final ListAdapter mAdapter;
+        static final ArrayList<FixedViewInfo> EMPTY_INFO_LIST =
+                new ArrayList<FixedViewInfo>();
+
+        // This ArrayList is assumed to NOT be null.
+        ArrayList<FixedViewInfo> mHeaderViewInfos;
+        ArrayList<FixedViewInfo> mFooterViewInfos;
+        private int mNumColumns = 1;
+        private int mRowHeight = -1;
+        boolean mAreAllFixedViewsSelectable;
+        private final boolean mIsFilterable;
+        private boolean mCachePlaceHoldView = true;
+        // From Recycle Bin or calling getView, this a question...
+        private boolean mCacheFirstHeaderView = false;
+
+        public HeaderViewGridAdapter(ArrayList<FixedViewInfo> headerViewInfos, ArrayList<FixedViewInfo> footViewInfos, ListAdapter adapter) {
+            mAdapter = adapter;
+            mIsFilterable = adapter instanceof Filterable;
+            if (headerViewInfos == null) {
+                mHeaderViewInfos = EMPTY_INFO_LIST;
+            } else {
+                mHeaderViewInfos = headerViewInfos;
+            }
+
+            if (footViewInfos == null) {
+                mFooterViewInfos = EMPTY_INFO_LIST;
+            } else {
+                mFooterViewInfos = footViewInfos;
+            }
+            mAreAllFixedViewsSelectable = areAllListInfosSelectable(mHeaderViewInfos)
+                    && areAllListInfosSelectable(mFooterViewInfos);
+        }
+
+        public void setNumColumns(int numColumns) {
+            if (numColumns < 1) {
+                return;
+            }
+            if (mNumColumns != numColumns) {
+                mNumColumns = numColumns;
+                notifyDataSetChanged();
+            }
+        }
+
+        public void setRowHeight(int height) {
+            mRowHeight = height;
+        }
+
+        public int getHeadersCount() {
+            return mHeaderViewInfos.size();
+        }
+
+        public int getFootersCount() {
+            return mFooterViewInfos.size();
+        }
+
+        @Override
+        public boolean isEmpty() {
+            return (mAdapter == null || mAdapter.isEmpty()) && getHeadersCount() == 0 && getFootersCount() == 0;
+        }
+
+        private boolean areAllListInfosSelectable(ArrayList<FixedViewInfo> infos) {
+            if (infos != null) {
+                for (FixedViewInfo info : infos) {
+                    if (!info.isSelectable) {
+                        return false;
+                    }
+                }
+            }
+            return true;
+        }
+
+        public boolean removeHeader(View v) {
+            for (int i = 0; i < mHeaderViewInfos.size(); i++) {
+                FixedViewInfo info = mHeaderViewInfos.get(i);
+                if (info.view == v) {
+                    mHeaderViewInfos.remove(i);
+                    mAreAllFixedViewsSelectable =
+                            areAllListInfosSelectable(mHeaderViewInfos) && areAllListInfosSelectable(mFooterViewInfos);
+                    mDataSetObservable.notifyChanged();
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public boolean removeFooter(View v) {
+            for (int i = 0; i < mFooterViewInfos.size(); i++) {
+                FixedViewInfo info = mFooterViewInfos.get(i);
+                if (info.view == v) {
+                    mFooterViewInfos.remove(i);
+                    mAreAllFixedViewsSelectable =
+                            areAllListInfosSelectable(mHeaderViewInfos) && areAllListInfosSelectable(mFooterViewInfos);
+                    mDataSetObservable.notifyChanged();
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        @Override
+        public int getCount() {
+            if (mAdapter != null) {
+                return (getFootersCount() + getHeadersCount()) * mNumColumns + getAdapterAndPlaceHolderCount();
+            } else {
+                return (getFootersCount() + getHeadersCount()) * mNumColumns;
+            }
+        }
+
+        @Override
+        public boolean areAllItemsEnabled() {
+            if (mAdapter != null) {
+                return mAreAllFixedViewsSelectable && mAdapter.areAllItemsEnabled();
+            } else {
+                return true;
+            }
+        }
+
+        private int getAdapterAndPlaceHolderCount() {
+            final int adapterCount = (int) (Math.ceil(1f * mAdapter.getCount() / mNumColumns) * mNumColumns);
+            return adapterCount;
+        }
+
+        @Override
+        public boolean isEnabled(int position) {
+            // Header (negative positions will throw an IndexOutOfBoundsException)
+            int numHeadersAndPlaceholders = getHeadersCount() * mNumColumns;
+            if (position < numHeadersAndPlaceholders) {
+                return position % mNumColumns == 0
+                        && mHeaderViewInfos.get(position / mNumColumns).isSelectable;
+            }
+
+            // Adapter
+            final int adjPosition = position - numHeadersAndPlaceholders;
+            int adapterCount = 0;
+            if (mAdapter != null) {
+                adapterCount = getAdapterAndPlaceHolderCount();
+                if (adjPosition < adapterCount) {
+                    return adjPosition < mAdapter.getCount() && mAdapter.isEnabled(adjPosition);
+                }
+            }
+
+            // Footer (off-limits positions will throw an IndexOutOfBoundsException)
+            final int footerPosition = adjPosition - adapterCount;
+            return footerPosition % mNumColumns == 0
+                    && mFooterViewInfos.get(footerPosition / mNumColumns).isSelectable;
+        }
+
+        @Override
+        public Object getItem(int position) {
+            // Header (negative positions will throw an ArrayIndexOutOfBoundsException)
+            int numHeadersAndPlaceholders = getHeadersCount() * mNumColumns;
+            if (position < numHeadersAndPlaceholders) {
+                if (position % mNumColumns == 0) {
+                    return mHeaderViewInfos.get(position / mNumColumns).data;
+                }
+                return null;
+            }
+
+            // Adapter
+            final int adjPosition = position - numHeadersAndPlaceholders;
+            int adapterCount = 0;
+            if (mAdapter != null) {
+                adapterCount = getAdapterAndPlaceHolderCount();
+                if (adjPosition < adapterCount) {
+                    if (adjPosition < mAdapter.getCount()) {
+                        return mAdapter.getItem(adjPosition);
+                    } else {
+                        return null;
+                    }
+                }
+            }
+
+            // Footer (off-limits positions will throw an IndexOutOfBoundsException)
+            final int footerPosition = adjPosition - adapterCount;
+            if (footerPosition % mNumColumns == 0) {
+                return mFooterViewInfos.get(footerPosition).data;
+            } else {
+                return null;
+            }
+        }
+
+        @Override
+        public long getItemId(int position) {
+            int numHeadersAndPlaceholders = getHeadersCount() * mNumColumns;
+            if (mAdapter != null && position >= numHeadersAndPlaceholders) {
+                int adjPosition = position - numHeadersAndPlaceholders;
+                int adapterCount = mAdapter.getCount();
+                if (adjPosition < adapterCount) {
+                    return mAdapter.getItemId(adjPosition);
+                }
+            }
+            return -1;
+        }
+
+        @Override
+        public boolean hasStableIds() {
+            if (mAdapter != null) {
+                return mAdapter.hasStableIds();
+            }
+            return false;
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            if (DEBUG) {
+                Log.d(LOG_TAG, String.format("getView: %s, reused: %s", position, convertView == null));
+            }
+            // Header (negative positions will throw an ArrayIndexOutOfBoundsException)
+            int numHeadersAndPlaceholders = getHeadersCount() * mNumColumns;
+            if (position < numHeadersAndPlaceholders) {
+                View headerViewContainer = mHeaderViewInfos
+                        .get(position / mNumColumns).viewContainer;
+                if (position % mNumColumns == 0) {
+                    return headerViewContainer;
+                } else {
+                    if (convertView == null) {
+                        convertView = new View(parent.getContext());
+                    }
+                    // We need to do this because GridView uses the height of the last item
+                    // in a row to determine the height for the entire row.
+                    convertView.setVisibility(View.INVISIBLE);
+                    convertView.setMinimumHeight(headerViewContainer.getHeight());
+                    return convertView;
+                }
+            }
+            // Adapter
+            final int adjPosition = position - numHeadersAndPlaceholders;
+            int adapterCount = 0;
+            if (mAdapter != null) {
+                adapterCount = getAdapterAndPlaceHolderCount();
+                if (adjPosition < adapterCount) {
+                    if (adjPosition < mAdapter.getCount()) {
+                        View view = mAdapter.getView(adjPosition, convertView, parent);
+                        return view;
+                    } else {
+                        if (convertView == null) {
+                            convertView = new View(parent.getContext());
+                        }
+                        convertView.setVisibility(View.INVISIBLE);
+                        convertView.setMinimumHeight(mRowHeight);
+                        return convertView;
+                    }
+                }
+            }
+            // Footer
+            final int footerPosition = adjPosition - adapterCount;
+            if (footerPosition < getCount()) {
+                View footViewContainer = mFooterViewInfos
+                        .get(footerPosition / mNumColumns).viewContainer;
+                if (position % mNumColumns == 0) {
+                    return footViewContainer;
+                } else {
+                    if (convertView == null) {
+                        convertView = new View(parent.getContext());
+                    }
+                    // We need to do this because GridView uses the height of the last item
+                    // in a row to determine the height for the entire row.
+                    convertView.setVisibility(View.INVISIBLE);
+                    convertView.setMinimumHeight(footViewContainer.getHeight());
+                    return convertView;
+                }
+            }
+            throw new ArrayIndexOutOfBoundsException(position);
+        }
+
+        @Override
+        public int getItemViewType(int position) {
+
+            final int numHeadersAndPlaceholders = getHeadersCount() * mNumColumns;
+            final int adapterViewTypeStart = mAdapter == null ? 0 : mAdapter.getViewTypeCount() - 1;
+            int type = AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER;
+            if (mCachePlaceHoldView) {
+                // Header
+                if (position < numHeadersAndPlaceholders) {
+                    if (position == 0) {
+                        if (mCacheFirstHeaderView) {
+                            type = adapterViewTypeStart + mHeaderViewInfos.size() + mFooterViewInfos.size() + 1 + 1;
+                        }
+                    }
+                    if (position % mNumColumns != 0) {
+                        type = adapterViewTypeStart + (position / mNumColumns + 1);
+                    }
+                }
+            }
+
+            // Adapter
+            final int adjPosition = position - numHeadersAndPlaceholders;
+            int adapterCount = 0;
+            if (mAdapter != null) {
+                adapterCount = getAdapterAndPlaceHolderCount();
+                if (adjPosition >= 0 && adjPosition < adapterCount) {
+                    if (adjPosition < mAdapter.getCount()) {
+                        type = mAdapter.getItemViewType(adjPosition);
+                    } else {
+                        if (mCachePlaceHoldView) {
+                            type = adapterViewTypeStart + mHeaderViewInfos.size() + 1;
+                        }
+                    }
+                }
+            }
+
+            if (mCachePlaceHoldView) {
+                // Footer
+                final int footerPosition = adjPosition - adapterCount;
+                if (footerPosition >= 0 && footerPosition < getCount() && (footerPosition % mNumColumns) != 0) {
+                    type = adapterViewTypeStart + mHeaderViewInfos.size() + 1 + (footerPosition / mNumColumns + 1);
+                }
+            }
+            if (DEBUG) {
+                Log.d(LOG_TAG, String.format("getItemViewType: pos: %s, result: %s", position, type, mCachePlaceHoldView, mCacheFirstHeaderView));
+            }
+            return type;
+        }
+
+        /**
+         * content view, content view holder, header[0], header and footer placeholder(s)
+         *
+         * @return
+         */
+        @Override
+        public int getViewTypeCount() {
+            int count = mAdapter == null ? 1 : mAdapter.getViewTypeCount();
+            if (mCachePlaceHoldView) {
+                int offset = mHeaderViewInfos.size() + 1 + mFooterViewInfos.size();
+                if (mCacheFirstHeaderView) {
+                    offset += 1;
+                }
+                count += offset;
+            }
+            if (DEBUG) {
+                Log.d(LOG_TAG, String.format("getViewTypeCount: %s", count));
+            }
+            return count;
+        }
+
+        @Override
+        public void registerDataSetObserver(DataSetObserver observer) {
+            mDataSetObservable.registerObserver(observer);
+            if (mAdapter != null) {
+                mAdapter.registerDataSetObserver(observer);
+            }
+        }
+
+        @Override
+        public void unregisterDataSetObserver(DataSetObserver observer) {
+            mDataSetObservable.unregisterObserver(observer);
+            if (mAdapter != null) {
+                mAdapter.unregisterDataSetObserver(observer);
+            }
+        }
+
+        @Override
+        public Filter getFilter() {
+            if (mIsFilterable) {
+                return ((Filterable) mAdapter).getFilter();
+            }
+            return null;
+        }
+
+        @Override
+        public ListAdapter getWrappedAdapter() {
+            return mAdapter;
+        }
+
+        public void notifyDataSetChanged() {
+            mDataSetObservable.notifyChanged();
+        }
+    }
+
+
+    /**
+     * Sets the selected item and positions the selection y pixels from the top edge of the ListView.
+     * (If in touch mode, the item will not be selected but it will still be positioned appropriately.)
+     *
+     * @param position     Index (starting at 0) of the data item to be selected.
+     * @param y            The distance from the top edge of the ListView (plus padding)
+     *                     that the item will be positioned.
+     *
+     * @see <a href="http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.4_r1/android/widget/ListView.java#ListView.setSelectionFromTop%28int%2Cint%29">Original code</a>
+     */
+    public void setSelectionFromTop(int position, int y) {
+        if (getAdapter() == null) {
+            return;
+        }
+
+        setSelection(position);
+        //setSelectionInt(position);
+
+        /*if (!isInTouchMode()) {
+            position = super.lookForSelectablePosition(position, true);
+            if (position >= 0) {
+                setNextSelectedPositionInt(position);
+            }
+        } else {
+            mResurrectToPosition = position;
+        }*/
+
+        /*
+        if (position >= 0) {
+            mLayoutMode = LAYOUT_SPECIFIC;
+            mSpecificTop = mListPadding.top + y;
+
+            if (mNeedSync) {
+                mSyncPosition = position;
+                mSyncRowId = getAdapter().getItemId(position);
+            }
+
+            if (mPositionScroller != null) {
+                mPositionScroller.stop();
+            }
+
+            requestLayout();
+        }
+        */
+    }
+
+}
diff --git a/src/third_parties/in/srain/cube/lapache-2.0.txt b/src/third_parties/in/srain/cube/lapache-2.0.txt
new file mode 100644 (file)
index 0000000..72f817f
--- /dev/null
@@ -0,0 +1,201 @@
+  Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
\ No newline at end of file
diff --git a/src/third_parties/michaelOrtiz/TouchImageViewCustom.java b/src/third_parties/michaelOrtiz/TouchImageViewCustom.java
new file mode 100644 (file)
index 0000000..9b0f5a0
--- /dev/null
@@ -0,0 +1,1277 @@
+/**
+ *   @author Michael Ortiz
+ *   @updated Patrick Lackemacher
+ *   @updated Babay88
+ *   @updated @ipsilondev
+ *   @updated hank-cp
+ *   @updated singpolyma
+ *   Copyright (c) 2012 Michael Ortiz
+ */
+
+package third_parties.michaelOrtiz;
+
+import com.owncloud.android.ui.preview.ImageViewCustom;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.PointF;
+import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Build.VERSION;
+import android.os.Build.VERSION_CODES;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.GestureDetector;
+import android.view.MotionEvent;
+import android.view.ScaleGestureDetector;
+import android.view.View;
+import android.view.animation.AccelerateDecelerateInterpolator;
+import android.widget.OverScroller;
+import android.widget.Scroller;
+
+/**
+ * Extends Android ImageView to include pinch zooming, panning, fling and double tap zoom.
+ */
+public class TouchImageViewCustom extends ImageViewCustom {
+    private static final String DEBUG = "DEBUG";
+       
+       //
+       // SuperMin and SuperMax multipliers. Determine how much the image can be
+       // zoomed below or above the zoom boundaries, before animating back to the
+       // min/max zoom boundary.
+       //
+       private static final float SUPER_MIN_MULTIPLIER = .75f;
+       private static final float SUPER_MAX_MULTIPLIER = 1.25f;
+
+    //
+    // Scale of image ranges from minScale to maxScale, where minScale == 1
+    // when the image is stretched to fit view.
+    //
+    private float normalizedScale;
+    
+    //
+    // Matrix applied to image. MSCALE_X and MSCALE_Y should always be equal.
+    // MTRANS_X and MTRANS_Y are the other values used. prevMatrix is the matrix
+    // saved prior to the screen rotating.
+    //
+       private Matrix matrix, prevMatrix;
+
+    private static enum State { NONE, DRAG, ZOOM, FLING, ANIMATE_ZOOM };
+    private State state;
+
+    private float minScale;
+    private float maxScale;
+    private float superMinScale;
+    private float superMaxScale;
+    private float[] m;
+    
+    private Context context;
+    private Fling fling;
+    
+    private ScaleType mScaleType;
+    
+    private boolean imageRenderedAtLeastOnce;
+    private boolean onDrawReady;
+    
+    private ZoomVariables delayedZoomVariables;
+
+    //
+    // Size of view and previous view size (ie before rotation)
+    //
+    private int viewWidth, viewHeight, prevViewWidth, prevViewHeight;
+    
+    //
+    // Size of image when it is stretched to fit view. Before and After rotation.
+    //
+    private float matchViewWidth, matchViewHeight, prevMatchViewWidth, prevMatchViewHeight;
+    
+    private ScaleGestureDetector mScaleDetector;
+    private GestureDetector mGestureDetector;
+    private GestureDetector.OnDoubleTapListener doubleTapListener = null;
+    private OnTouchListener userTouchListener = null;
+    private OnTouchImageViewListener touchImageViewListener = null;
+
+    public TouchImageViewCustom(Context context) {
+        super(context);
+        sharedConstructing(context);
+    }
+
+    public TouchImageViewCustom(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        sharedConstructing(context);
+    }
+    
+    public TouchImageViewCustom(Context context, AttributeSet attrs, int defStyle) {
+       super(context, attrs, defStyle);
+       sharedConstructing(context);
+    }
+    
+    private void sharedConstructing(Context context) {
+        super.setClickable(true);
+        this.context = context;
+        mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
+        mGestureDetector = new GestureDetector(context, new GestureListener());
+        matrix = new Matrix();
+        prevMatrix = new Matrix();
+        m = new float[9];
+        normalizedScale = 1;
+        if (mScaleType == null) {
+               mScaleType = ScaleType.FIT_CENTER;
+        }
+        minScale = 1;
+        maxScale = 3;
+        superMinScale = SUPER_MIN_MULTIPLIER * minScale;
+        superMaxScale = SUPER_MAX_MULTIPLIER * maxScale;
+        setImageMatrix(matrix);
+        setScaleType(ScaleType.MATRIX);
+        setState(State.NONE);
+        onDrawReady = false;
+        super.setOnTouchListener(new PrivateOnTouchListener());
+    }
+
+    @Override
+    public void setOnTouchListener(View.OnTouchListener l) {
+        userTouchListener = l;
+    }
+    
+    public void setOnTouchImageViewListener(OnTouchImageViewListener l) {
+       touchImageViewListener = l;
+    }
+
+    public void setOnDoubleTapListener(GestureDetector.OnDoubleTapListener l) {
+        doubleTapListener = l;
+    }
+
+    @Override
+    public void setImageResource(int resId) {
+       super.setImageResource(resId);
+       savePreviousImageValues();
+       fitImageToView();
+    }
+    
+    @Override
+    public void setImageBitmap(Bitmap bm) {
+       super.setImageBitmap(bm);
+       savePreviousImageValues();
+       fitImageToView();
+    }
+    
+    @Override
+    public void setImageDrawable(Drawable drawable) {
+       super.setImageDrawable(drawable);
+       savePreviousImageValues();
+       fitImageToView();
+    }
+    
+    @Override
+    public void setImageURI(Uri uri) {
+       super.setImageURI(uri);
+       savePreviousImageValues();
+       fitImageToView();
+    }
+    
+    @Override
+    public void setScaleType(ScaleType type) {
+       if (type == ScaleType.FIT_START || type == ScaleType.FIT_END) {
+               throw new UnsupportedOperationException("TouchImageView does not support FIT_START or FIT_END");
+       }
+       if (type == ScaleType.MATRIX) {
+               super.setScaleType(ScaleType.MATRIX);
+               
+       } else {
+               mScaleType = type;
+               if (onDrawReady) {
+                       //
+                       // If the image is already rendered, scaleType has been called programmatically
+                       // and the TouchImageView should be updated with the new scaleType.
+                       //
+                       setZoom(this);
+               }
+       }
+    }
+    
+    @Override
+    public ScaleType getScaleType() {
+       return mScaleType;
+    }
+    
+    /**
+     * Returns false if image is in initial, unzoomed state. False, otherwise.
+     * @return true if image is zoomed
+     */
+    public boolean isZoomed() {
+       return normalizedScale != 1;
+    }
+    
+    /**
+     * Return a Rect representing the zoomed image.
+     * @return rect representing zoomed image
+     */
+    public RectF getZoomedRect() {
+       if (mScaleType == ScaleType.FIT_XY) {
+               throw new UnsupportedOperationException("getZoomedRect() not supported with FIT_XY");
+       }
+       PointF topLeft = transformCoordTouchToBitmap(0, 0, true);
+       PointF bottomRight = transformCoordTouchToBitmap(viewWidth, viewHeight, true);
+       
+       float w = getDrawable().getIntrinsicWidth();
+       float h = getDrawable().getIntrinsicHeight();
+       return new RectF(topLeft.x / w, topLeft.y / h, bottomRight.x / w, bottomRight.y / h);
+    }
+    
+    /**
+     * Save the current matrix and view dimensions
+     * in the prevMatrix and prevView variables.
+     */
+    private void savePreviousImageValues() {
+       if (matrix != null && viewHeight != 0 && viewWidth != 0) {
+               matrix.getValues(m);
+               prevMatrix.setValues(m);
+               prevMatchViewHeight = matchViewHeight;
+               prevMatchViewWidth = matchViewWidth;
+               prevViewHeight = viewHeight;
+               prevViewWidth = viewWidth;
+       }
+    }
+    
+    @Override
+    public Parcelable onSaveInstanceState() {
+       Bundle bundle = new Bundle();
+       bundle.putParcelable("instanceState", super.onSaveInstanceState());
+       bundle.putFloat("saveScale", normalizedScale);
+       bundle.putFloat("matchViewHeight", matchViewHeight);
+       bundle.putFloat("matchViewWidth", matchViewWidth);
+       bundle.putInt("viewWidth", viewWidth);
+       bundle.putInt("viewHeight", viewHeight);
+       matrix.getValues(m);
+       bundle.putFloatArray("matrix", m);
+       bundle.putBoolean("imageRendered", imageRenderedAtLeastOnce);
+       return bundle;
+    }
+    
+    @Override
+    public void onRestoreInstanceState(Parcelable state) {
+       if (state instanceof Bundle) {
+               Bundle bundle = (Bundle) state;
+               normalizedScale = bundle.getFloat("saveScale");
+               m = bundle.getFloatArray("matrix");
+               prevMatrix.setValues(m);
+               prevMatchViewHeight = bundle.getFloat("matchViewHeight");
+               prevMatchViewWidth = bundle.getFloat("matchViewWidth");
+               prevViewHeight = bundle.getInt("viewHeight");
+               prevViewWidth = bundle.getInt("viewWidth");
+               imageRenderedAtLeastOnce = bundle.getBoolean("imageRendered");
+               super.onRestoreInstanceState(bundle.getParcelable("instanceState"));
+               return;
+       }
+
+       super.onRestoreInstanceState(state);
+    }
+    
+    @Override
+    protected void onDraw(Canvas canvas) {
+       onDrawReady = true;
+       imageRenderedAtLeastOnce = true;
+       if (delayedZoomVariables != null) {
+               setZoom(delayedZoomVariables.scale, delayedZoomVariables.focusX, delayedZoomVariables.focusY, delayedZoomVariables.scaleType);
+               delayedZoomVariables = null;
+       }
+       super.onDraw(canvas);
+    }
+    
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+       super.onConfigurationChanged(newConfig);
+       savePreviousImageValues();
+    }
+    
+    /**
+     * Get the max zoom multiplier.
+     * @return max zoom multiplier.
+     */
+    public float getMaxZoom() {
+       return maxScale;
+    }
+
+    /**
+     * Set the max zoom multiplier. Default value: 3.
+     * @param max max zoom multiplier.
+     */
+    public void setMaxZoom(float max) {
+        maxScale = max;
+        superMaxScale = SUPER_MAX_MULTIPLIER * maxScale;
+    }
+    
+    /**
+     * Get the min zoom multiplier.
+     * @return min zoom multiplier.
+     */
+    public float getMinZoom() {
+       return minScale;
+    }
+    
+    /**
+     * Get the current zoom. This is the zoom relative to the initial
+     * scale, not the original resource.
+     * @return current zoom multiplier.
+     */
+    public float getCurrentZoom() {
+       return normalizedScale;
+    }
+    
+    /**
+     * Set the min zoom multiplier. Default value: 1.
+     * @param min min zoom multiplier.
+     */
+    public void setMinZoom(float min) {
+       minScale = min;
+       superMinScale = SUPER_MIN_MULTIPLIER * minScale;
+    }
+    
+    /**
+     * Reset zoom and translation to initial state.
+     */
+    public void resetZoom() {
+       normalizedScale = 1;
+       fitImageToView();
+    }
+    
+    /**
+     * Set zoom to the specified scale. Image will be centered by default.
+     * @param scale
+     */
+    public void setZoom(float scale) {
+       setZoom(scale, 0.5f, 0.5f);
+    }
+    
+    /**
+     * Set zoom to the specified scale. Image will be centered around the point
+     * (focusX, focusY). These floats range from 0 to 1 and denote the focus point
+     * as a fraction from the left and top of the view. For example, the top left 
+     * corner of the image would be (0, 0). And the bottom right corner would be (1, 1).
+     * @param scale
+     * @param focusX
+     * @param focusY
+     */
+    public void setZoom(float scale, float focusX, float focusY) {
+       setZoom(scale, focusX, focusY, mScaleType);
+    }
+    
+    /**
+     * Set zoom to the specified scale. Image will be centered around the point
+     * (focusX, focusY). These floats range from 0 to 1 and denote the focus point
+     * as a fraction from the left and top of the view. For example, the top left 
+     * corner of the image would be (0, 0). And the bottom right corner would be (1, 1).
+     * @param scale
+     * @param focusX
+     * @param focusY
+     * @param scaleType
+     */
+    public void setZoom(float scale, float focusX, float focusY, ScaleType scaleType) {
+       //
+       // setZoom can be called before the image is on the screen, but at this point, 
+       // image and view sizes have not yet been calculated in onMeasure. Thus, we should
+       // delay calling setZoom until the view has been measured.
+       //
+       if (!onDrawReady) {
+               delayedZoomVariables = new ZoomVariables(scale, focusX, focusY, scaleType);
+               return;
+       }
+       
+       if (scaleType != mScaleType) {
+               setScaleType(scaleType);
+       }
+       resetZoom();
+       scaleImage(scale, viewWidth / 2, viewHeight / 2, true);
+       matrix.getValues(m);
+       m[Matrix.MTRANS_X] = -((focusX * getImageWidth()) - (viewWidth * 0.5f));
+       m[Matrix.MTRANS_Y] = -((focusY * getImageHeight()) - (viewHeight * 0.5f));
+       matrix.setValues(m);
+       fixTrans();
+       setImageMatrix(matrix);
+    }
+    
+    /**
+     * Set zoom parameters equal to another TouchImageView. Including scale, position,
+     * and ScaleType.
+     * @param img
+     */
+    public void setZoom(TouchImageViewCustom img) {
+       PointF center = img.getScrollPosition();
+       setZoom(img.getCurrentZoom(), center.x, center.y, img.getScaleType());
+    }
+    
+    /**
+     * Return the point at the center of the zoomed image. The PointF coordinates range
+     * in value between 0 and 1 and the focus point is denoted as a fraction from the left 
+     * and top of the view. For example, the top left corner of the image would be (0, 0). 
+     * And the bottom right corner would be (1, 1).
+     * @return PointF representing the scroll position of the zoomed image.
+     */
+    public PointF getScrollPosition() {
+       Drawable drawable = getDrawable();
+       if (drawable == null) {
+               return null;
+       }
+       int drawableWidth = drawable.getIntrinsicWidth();
+        int drawableHeight = drawable.getIntrinsicHeight();
+        
+        PointF point = transformCoordTouchToBitmap(viewWidth / 2, viewHeight / 2, true);
+        point.x /= drawableWidth;
+        point.y /= drawableHeight;
+        return point;
+    }
+    
+    /**
+     * Set the focus point of the zoomed image. The focus points are denoted as a fraction from the
+     * left and top of the view. The focus points can range in value between 0 and 1. 
+     * @param focusX
+     * @param focusY
+     */
+    public void setScrollPosition(float focusX, float focusY) {
+       setZoom(normalizedScale, focusX, focusY);
+    }
+    
+    /**
+     * Performs boundary checking and fixes the image matrix if it 
+     * is out of bounds.
+     */
+    private void fixTrans() {
+        matrix.getValues(m);
+        float transX = m[Matrix.MTRANS_X];
+        float transY = m[Matrix.MTRANS_Y];
+        
+        float fixTransX = getFixTrans(transX, viewWidth, getImageWidth());
+        float fixTransY = getFixTrans(transY, viewHeight, getImageHeight());
+        
+        if (fixTransX != 0 || fixTransY != 0) {
+            matrix.postTranslate(fixTransX, fixTransY);
+        }
+    }
+    
+    /**
+     * When transitioning from zooming from focus to zoom from center (or vice versa)
+     * the image can become unaligned within the view. This is apparent when zooming
+     * quickly. When the content size is less than the view size, the content will often
+     * be centered incorrectly within the view. fixScaleTrans first calls fixTrans() and 
+     * then makes sure the image is centered correctly within the view.
+     */
+    private void fixScaleTrans() {
+       fixTrans();
+       matrix.getValues(m);
+       if (getImageWidth() < viewWidth) {
+               m[Matrix.MTRANS_X] = (viewWidth - getImageWidth()) / 2;
+       }
+       
+       if (getImageHeight() < viewHeight) {
+               m[Matrix.MTRANS_Y] = (viewHeight - getImageHeight()) / 2;
+       }
+       matrix.setValues(m);
+    }
+
+    private float getFixTrans(float trans, float viewSize, float contentSize) {
+        float minTrans, maxTrans;
+
+        if (contentSize <= viewSize) {
+            minTrans = 0;
+            maxTrans = viewSize - contentSize;
+            
+        } else {
+            minTrans = viewSize - contentSize;
+            maxTrans = 0;
+        }
+
+        if (trans < minTrans)
+            return -trans + minTrans;
+        if (trans > maxTrans)
+            return -trans + maxTrans;
+        return 0;
+    }
+    
+    private float getFixDragTrans(float delta, float viewSize, float contentSize) {
+        if (contentSize <= viewSize) {
+            return 0;
+        }
+        return delta;
+    }
+    
+    private float getImageWidth() {
+       return matchViewWidth * normalizedScale;
+    }
+    
+    private float getImageHeight() {
+       return matchViewHeight * normalizedScale;
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        Drawable drawable = getDrawable();
+        if (drawable == null || drawable.getIntrinsicWidth() == 0 || drawable.getIntrinsicHeight() == 0) {
+               setMeasuredDimension(0, 0);
+               return;
+        }
+        
+        int drawableWidth = drawable.getIntrinsicWidth();
+        int drawableHeight = drawable.getIntrinsicHeight();
+        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
+        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
+        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+        viewWidth = setViewSize(widthMode, widthSize, drawableWidth);
+        viewHeight = setViewSize(heightMode, heightSize, drawableHeight);
+        
+        //
+        // Set view dimensions
+        //
+        setMeasuredDimension(viewWidth, viewHeight);
+        
+        //
+        // Fit content within view
+        //
+        fitImageToView();
+    }
+    
+    /**
+     * If the normalizedScale is equal to 1, then the image is made to fit the screen. Otherwise,
+     * it is made to fit the screen according to the dimensions of the previous image matrix. This
+     * allows the image to maintain its zoom after rotation.
+     */
+    private void fitImageToView() {
+       Drawable drawable = getDrawable();
+        if (drawable == null || drawable.getIntrinsicWidth() == 0 || drawable.getIntrinsicHeight() == 0) {
+               return;
+        }
+        if (matrix == null || prevMatrix == null) {
+               return;
+        }
+        
+        int drawableWidth = drawable.getIntrinsicWidth();
+        int drawableHeight = drawable.getIntrinsicHeight();
+       
+       //
+       // Scale image for view
+       //
+        float scaleX = (float) viewWidth / drawableWidth;
+        float scaleY = (float) viewHeight / drawableHeight;
+        
+        switch (mScaleType) {
+        case CENTER:
+               scaleX = scaleY = 1;
+               break;
+               
+        case CENTER_CROP:
+               scaleX = scaleY = Math.max(scaleX, scaleY);
+               break;
+               
+        case CENTER_INSIDE:
+               scaleX = scaleY = Math.min(1, Math.min(scaleX, scaleY));
+               
+        case FIT_CENTER:
+               scaleX = scaleY = Math.min(scaleX, scaleY);
+               break;
+               
+        case FIT_XY:
+               break;
+               
+       default:
+               //
+               // FIT_START and FIT_END not supported
+               //
+               throw new UnsupportedOperationException("TouchImageView does not support FIT_START or FIT_END");
+               
+        }
+
+        //
+        // Center the image
+        //
+        float redundantXSpace = viewWidth - (scaleX * drawableWidth);
+        float redundantYSpace = viewHeight - (scaleY * drawableHeight);
+        matchViewWidth = viewWidth - redundantXSpace;
+        matchViewHeight = viewHeight - redundantYSpace;
+        if (!isZoomed() && !imageRenderedAtLeastOnce) {
+               //
+               // Stretch and center image to fit view
+               //
+               matrix.setScale(scaleX, scaleY);
+               matrix.postTranslate(redundantXSpace / 2, redundantYSpace / 2);
+               normalizedScale = 1;
+               
+        } else {
+               //
+               // These values should never be 0 or we will set viewWidth and viewHeight
+               // to NaN in translateMatrixAfterRotate. To avoid this, call savePreviousImageValues
+               // to set them equal to the current values.
+               //
+               if (prevMatchViewWidth == 0 || prevMatchViewHeight == 0) {
+                       savePreviousImageValues();
+               }
+               
+               prevMatrix.getValues(m);
+               
+               //
+               // Rescale Matrix after rotation
+               //
+               m[Matrix.MSCALE_X] = matchViewWidth / drawableWidth * normalizedScale;
+               m[Matrix.MSCALE_Y] = matchViewHeight / drawableHeight * normalizedScale;
+               
+               //
+               // TransX and TransY from previous matrix
+               //
+            float transX = m[Matrix.MTRANS_X];
+            float transY = m[Matrix.MTRANS_Y];
+            
+            //
+            // Width
+            //
+            float prevActualWidth = prevMatchViewWidth * normalizedScale;
+            float actualWidth = getImageWidth();
+            translateMatrixAfterRotate(Matrix.MTRANS_X, transX, prevActualWidth, actualWidth, prevViewWidth, viewWidth, drawableWidth);
+            
+            //
+            // Height
+            //
+            float prevActualHeight = prevMatchViewHeight * normalizedScale;
+            float actualHeight = getImageHeight();
+            translateMatrixAfterRotate(Matrix.MTRANS_Y, transY, prevActualHeight, actualHeight, prevViewHeight, viewHeight, drawableHeight);
+            
+            //
+            // Set the matrix to the adjusted scale and translate values.
+            //
+            matrix.setValues(m);
+        }
+        fixTrans();
+        setImageMatrix(matrix);
+    }
+    
+    /**
+     * Set view dimensions based on layout params
+     * 
+     * @param mode 
+     * @param size
+     * @param drawableWidth
+     * @return
+     */
+    private int setViewSize(int mode, int size, int drawableWidth) {
+       int viewSize;
+       switch (mode) {
+               case MeasureSpec.EXACTLY:
+                       viewSize = size;
+                       break;
+                       
+               case MeasureSpec.AT_MOST:
+                       viewSize = Math.min(drawableWidth, size);
+                       break;
+                       
+               case MeasureSpec.UNSPECIFIED:
+                       viewSize = drawableWidth;
+                       break;
+                       
+               default:
+                       viewSize = size;
+                       break;
+               }
+       return viewSize;
+    }
+    
+    /**
+     * After rotating, the matrix needs to be translated. This function finds the area of image 
+     * which was previously centered and adjusts translations so that is again the center, post-rotation.
+     * 
+     * @param axis Matrix.MTRANS_X or Matrix.MTRANS_Y
+     * @param trans the value of trans in that axis before the rotation
+     * @param prevImageSize the width/height of the image before the rotation
+     * @param imageSize width/height of the image after rotation
+     * @param prevViewSize width/height of view before rotation
+     * @param viewSize width/height of view after rotation
+     * @param drawableSize width/height of drawable
+     */
+    private void translateMatrixAfterRotate(int axis, float trans, float prevImageSize, float imageSize, int prevViewSize, int viewSize, int drawableSize) {
+       if (imageSize < viewSize) {
+               //
+               // The width/height of image is less than the view's width/height. Center it.
+               //
+               m[axis] = (viewSize - (drawableSize * m[Matrix.MSCALE_X])) * 0.5f;
+               
+        } else if (trans > 0) {
+               //
+               // The image is larger than the view, but was not before rotation. Center it.
+               //
+               m[axis] = -((imageSize - viewSize) * 0.5f);
+               
+        } else {
+               //
+               // Find the area of the image which was previously centered in the view. Determine its distance
+               // from the left/top side of the view as a fraction of the entire image's width/height. Use that percentage
+               // to calculate the trans in the new view width/height.
+               //
+               float percentage = (Math.abs(trans) + (0.5f * prevViewSize)) / prevImageSize;
+               m[axis] = -((percentage * imageSize) - (viewSize * 0.5f));
+        }
+    }
+    
+    private void setState(State state) {
+       this.state = state;
+    }
+    
+    public boolean canScrollHorizontallyFroyo(int direction) {
+        return canScrollHorizontally(direction);
+    }
+    
+    @Override
+    public boolean canScrollHorizontally(int direction) {
+       matrix.getValues(m);
+       float x = m[Matrix.MTRANS_X];
+       
+       if (getImageWidth() < viewWidth) {
+               return false;
+               
+       } else if (x >= -1 && direction < 0) {
+               return false;
+               
+       } else if (Math.abs(x) + viewWidth + 1 >= getImageWidth() && direction > 0) {
+               return false;
+       }
+       
+       return true;
+    }
+    
+    /**
+     * Gesture Listener detects a single click or long click and passes that on
+     * to the view's listener.
+     * @author Ortiz
+     *
+     */
+    private class GestureListener extends GestureDetector.SimpleOnGestureListener {
+       
+        @Override
+        public boolean onSingleTapConfirmed(MotionEvent e)
+        {
+            if(doubleTapListener != null) {
+               return doubleTapListener.onSingleTapConfirmed(e);
+            }
+               return performClick();
+        }
+        
+        @Override
+        public void onLongPress(MotionEvent e)
+        {
+               performLongClick();
+        }
+        
+        @Override
+        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)
+        {
+               if (fling != null) {
+                       //
+                       // If a previous fling is still active, it should be cancelled so that two flings
+                       // are not run simultaenously.
+                       //
+                       fling.cancelFling();
+               }
+               fling = new Fling((int) velocityX, (int) velocityY);
+               compatPostOnAnimation(fling);
+               return super.onFling(e1, e2, velocityX, velocityY);
+        }
+        
+        @Override
+        public boolean onDoubleTap(MotionEvent e) {
+               boolean consumed = false;
+            if(doubleTapListener != null) {
+               consumed = doubleTapListener.onDoubleTap(e);
+            }
+               if (state == State.NONE) {
+                       float targetZoom = (normalizedScale == minScale) ? maxScale : minScale;
+                       DoubleTapZoom doubleTap = new DoubleTapZoom(targetZoom, e.getX(), e.getY(), false);
+                       compatPostOnAnimation(doubleTap);
+                       consumed = true;
+               }
+               return consumed;
+        }
+
+        @Override
+        public boolean onDoubleTapEvent(MotionEvent e) {
+            if(doubleTapListener != null) {
+               return doubleTapListener.onDoubleTapEvent(e);
+            }
+            return false;
+        }
+    }
+    
+    public interface OnTouchImageViewListener {
+       public void onMove();
+    }
+    
+    /**
+     * Responsible for all touch events. Handles the heavy lifting of drag and also sends
+     * touch events to Scale Detector and Gesture Detector.
+     * @author Ortiz
+     *
+     */
+    private class PrivateOnTouchListener implements OnTouchListener {
+       
+       //
+        // Remember last point position for dragging
+        //
+        private PointF last = new PointF();
+       
+       @Override
+        public boolean onTouch(View v, MotionEvent event) {
+            mScaleDetector.onTouchEvent(event);
+            mGestureDetector.onTouchEvent(event);
+            PointF curr = new PointF(event.getX(), event.getY());
+            
+            if (state == State.NONE || state == State.DRAG || state == State.FLING) {
+                   switch (event.getAction()) {
+                       case MotionEvent.ACTION_DOWN:
+                               last.set(curr);
+                           if (fling != null)
+                               fling.cancelFling();
+                           setState(State.DRAG);
+                           break;
+                           
+                       case MotionEvent.ACTION_MOVE:
+                           if (state == State.DRAG) {
+                               float deltaX = curr.x - last.x;
+                               float deltaY = curr.y - last.y;
+                               float fixTransX = getFixDragTrans(deltaX, viewWidth, getImageWidth());
+                               float fixTransY = getFixDragTrans(deltaY, viewHeight, getImageHeight());
+                               matrix.postTranslate(fixTransX, fixTransY);
+                               fixTrans();
+                               last.set(curr.x, curr.y);
+                           }
+                           break;
+       
+                       case MotionEvent.ACTION_UP:
+                       case MotionEvent.ACTION_POINTER_UP:
+                           setState(State.NONE);
+                           break;
+                   }
+            }
+            
+            setImageMatrix(matrix);
+            
+            //
+               // User-defined OnTouchListener
+               //
+               if(userTouchListener != null) {
+                       userTouchListener.onTouch(v, event);
+               }
+            
+               //
+               // OnTouchImageViewListener is set: TouchImageView dragged by user.
+               //
+               if (touchImageViewListener != null) {
+                       touchImageViewListener.onMove();
+               }
+               
+            //
+            // indicate event was handled
+            //
+            return true;
+        }
+    }
+
+    /**
+     * ScaleListener detects user two finger scaling and scales image.
+     * @author Ortiz
+     *
+     */
+    private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
+        @Override
+        public boolean onScaleBegin(ScaleGestureDetector detector) {
+            setState(State.ZOOM);
+            return true;
+        }
+
+        @Override
+        public boolean onScale(ScaleGestureDetector detector) {
+               scaleImage(detector.getScaleFactor(), detector.getFocusX(), detector.getFocusY(), true);
+               
+               //
+               // OnTouchImageViewListener is set: TouchImageView pinch zoomed by user.
+               //
+               if (touchImageViewListener != null) {
+                       touchImageViewListener.onMove();
+               }
+            return true;
+        }
+        
+        @Override
+        public void onScaleEnd(ScaleGestureDetector detector) {
+               super.onScaleEnd(detector);
+               setState(State.NONE);
+               boolean animateToZoomBoundary = false;
+               float targetZoom = normalizedScale;
+               if (normalizedScale > maxScale) {
+                       targetZoom = maxScale;
+                       animateToZoomBoundary = true;
+                       
+               } else if (normalizedScale < minScale) {
+                       targetZoom = minScale;
+                       animateToZoomBoundary = true;
+               }
+               
+               if (animateToZoomBoundary) {
+                       DoubleTapZoom doubleTap = new DoubleTapZoom(targetZoom, viewWidth / 2, viewHeight / 2, true);
+                       compatPostOnAnimation(doubleTap);
+               }
+        }
+    }
+    
+    private void scaleImage(double deltaScale, float focusX, float focusY, boolean stretchImageToSuper) {
+       
+       float lowerScale, upperScale;
+       if (stretchImageToSuper) {
+               lowerScale = superMinScale;
+               upperScale = superMaxScale;
+               
+       } else {
+               lowerScale = minScale;
+               upperScale = maxScale;
+       }
+       
+       float origScale = normalizedScale;
+        normalizedScale *= deltaScale;
+        if (normalizedScale > upperScale) {
+            normalizedScale = upperScale;
+            deltaScale = upperScale / origScale;
+        } else if (normalizedScale < lowerScale) {
+            normalizedScale = lowerScale;
+            deltaScale = lowerScale / origScale;
+        }
+        
+        matrix.postScale((float) deltaScale, (float) deltaScale, focusX, focusY);
+        fixScaleTrans();
+    }
+    
+    /**
+     * DoubleTapZoom calls a series of runnables which apply
+     * an animated zoom in/out graphic to the image.
+     * @author Ortiz
+     *
+     */
+    private class DoubleTapZoom implements Runnable {
+       
+       private long startTime;
+       private static final float ZOOM_TIME = 500;
+       private float startZoom, targetZoom;
+       private float bitmapX, bitmapY;
+       private boolean stretchImageToSuper;
+       private AccelerateDecelerateInterpolator interpolator = new AccelerateDecelerateInterpolator();
+       private PointF startTouch;
+       private PointF endTouch;
+
+       DoubleTapZoom(float targetZoom, float focusX, float focusY, boolean stretchImageToSuper) {
+               setState(State.ANIMATE_ZOOM);
+               startTime = System.currentTimeMillis();
+               this.startZoom = normalizedScale;
+               this.targetZoom = targetZoom;
+               this.stretchImageToSuper = stretchImageToSuper;
+               PointF bitmapPoint = transformCoordTouchToBitmap(focusX, focusY, false);
+               this.bitmapX = bitmapPoint.x;
+               this.bitmapY = bitmapPoint.y;
+               
+               //
+               // Used for translating image during scaling
+               //
+               startTouch = transformCoordBitmapToTouch(bitmapX, bitmapY);
+               endTouch = new PointF(viewWidth / 2, viewHeight / 2);
+       }
+
+               @Override
+               public void run() {
+                       float t = interpolate();
+                       double deltaScale = calculateDeltaScale(t);
+                       scaleImage(deltaScale, bitmapX, bitmapY, stretchImageToSuper);
+                       translateImageToCenterTouchPosition(t);
+                       fixScaleTrans();
+                       setImageMatrix(matrix);
+                       
+                       //
+                       // OnTouchImageViewListener is set: double tap runnable updates listener
+                       // with every frame.
+                       //
+                       if (touchImageViewListener != null) {
+                               touchImageViewListener.onMove();
+                       }
+                       
+                       if (t < 1f) {
+                               //
+                               // We haven't finished zooming
+                               //
+                               compatPostOnAnimation(this);
+                               
+                       } else {
+                               //
+                               // Finished zooming
+                               //
+                               setState(State.NONE);
+                       }
+               }
+               
+               /**
+                * Interpolate between where the image should start and end in order to translate
+                * the image so that the point that is touched is what ends up centered at the end
+                * of the zoom.
+                * @param t
+                */
+               private void translateImageToCenterTouchPosition(float t) {
+                       float targetX = startTouch.x + t * (endTouch.x - startTouch.x);
+                       float targetY = startTouch.y + t * (endTouch.y - startTouch.y);
+                       PointF curr = transformCoordBitmapToTouch(bitmapX, bitmapY);
+                       matrix.postTranslate(targetX - curr.x, targetY - curr.y);
+               }
+               
+               /**
+                * Use interpolator to get t
+                * @return
+                */
+               private float interpolate() {
+                       long currTime = System.currentTimeMillis();
+                       float elapsed = (currTime - startTime) / ZOOM_TIME;
+                       elapsed = Math.min(1f, elapsed);
+                       return interpolator.getInterpolation(elapsed);
+               }
+               
+               /**
+                * Interpolate the current targeted zoom and get the delta
+                * from the current zoom.
+                * @param t
+                * @return
+                */
+               private double calculateDeltaScale(float t) {
+                       double zoom = startZoom + t * (targetZoom - startZoom);
+                       return zoom / normalizedScale;
+               }
+    }
+    
+    /**
+     * This function will transform the coordinates in the touch event to the coordinate 
+     * system of the drawable that the imageview contain
+     * @param x x-coordinate of touch event
+     * @param y y-coordinate of touch event
+     * @param clipToBitmap Touch event may occur within view, but outside image content. True, to clip return value
+     *                         to the bounds of the bitmap size.
+     * @return Coordinates of the point touched, in the coordinate system of the original drawable.
+     */
+    private PointF transformCoordTouchToBitmap(float x, float y, boolean clipToBitmap) {
+         matrix.getValues(m);
+         float origW = getDrawable().getIntrinsicWidth();
+         float origH = getDrawable().getIntrinsicHeight();
+         float transX = m[Matrix.MTRANS_X];
+         float transY = m[Matrix.MTRANS_Y];
+         float finalX = ((x - transX) * origW) / getImageWidth();
+         float finalY = ((y - transY) * origH) / getImageHeight();
+         
+         if (clipToBitmap) {
+                finalX = Math.min(Math.max(finalX, 0), origW);
+                finalY = Math.min(Math.max(finalY, 0), origH);
+         }
+         
+         return new PointF(finalX , finalY);
+    }
+    
+    /**
+     * Inverse of transformCoordTouchToBitmap. This function will transform the coordinates in the
+     * drawable's coordinate system to the view's coordinate system.
+     * @param bx x-coordinate in original bitmap coordinate system
+     * @param by y-coordinate in original bitmap coordinate system
+     * @return Coordinates of the point in the view's coordinate system.
+     */
+    private PointF transformCoordBitmapToTouch(float bx, float by) {
+        matrix.getValues(m);        
+        float origW = getDrawable().getIntrinsicWidth();
+        float origH = getDrawable().getIntrinsicHeight();
+        float px = bx / origW;
+        float py = by / origH;
+        float finalX = m[Matrix.MTRANS_X] + getImageWidth() * px;
+        float finalY = m[Matrix.MTRANS_Y] + getImageHeight() * py;
+        return new PointF(finalX , finalY);
+    }
+    
+    /**
+     * Fling launches sequential runnables which apply
+     * the fling graphic to the image. The values for the translation
+     * are interpolated by the Scroller.
+     * @author Ortiz
+     *
+     */
+    private class Fling implements Runnable {
+       
+        CompatScroller scroller;
+       int currX, currY;
+       
+       Fling(int velocityX, int velocityY) {
+               setState(State.FLING);
+               scroller = new CompatScroller(context);
+               matrix.getValues(m);
+               
+               int startX = (int) m[Matrix.MTRANS_X];
+               int startY = (int) m[Matrix.MTRANS_Y];
+               int minX, maxX, minY, maxY;
+               
+               if (getImageWidth() > viewWidth) {
+                       minX = viewWidth - (int) getImageWidth();
+                       maxX = 0;
+                       
+               } else {
+                       minX = maxX = startX;
+               }
+               
+               if (getImageHeight() > viewHeight) {
+                       minY = viewHeight - (int) getImageHeight();
+                       maxY = 0;
+                       
+               } else {
+                       minY = maxY = startY;
+               }
+               
+               scroller.fling(startX, startY, (int) velocityX, (int) velocityY, minX,
+                    maxX, minY, maxY);
+               currX = startX;
+               currY = startY;
+       }
+       
+       public void cancelFling() {
+               if (scroller != null) {
+                       setState(State.NONE);
+                       scroller.forceFinished(true);
+               }
+       }
+       
+               @Override
+               public void run() {
+                       
+                       //
+                       // OnTouchImageViewListener is set: TouchImageView listener has been flung by user.
+                       // Listener runnable updated with each frame of fling animation.
+                       //
+                       if (touchImageViewListener != null) {
+                               touchImageViewListener.onMove();
+                       }
+                       
+                       if (scroller.isFinished()) {
+                       scroller = null;
+                       return;
+               }
+                       
+                       if (scroller.computeScrollOffset()) {
+                       int newX = scroller.getCurrX();
+                   int newY = scroller.getCurrY();
+                   int transX = newX - currX;
+                   int transY = newY - currY;
+                   currX = newX;
+                   currY = newY;
+                   matrix.postTranslate(transX, transY);
+                   fixTrans();
+                   setImageMatrix(matrix);
+                   compatPostOnAnimation(this);
+               }
+               }
+    }
+    
+    @TargetApi(Build.VERSION_CODES.GINGERBREAD)
+       private class CompatScroller {
+       Scroller scroller;
+       OverScroller overScroller;
+       boolean isPreGingerbread;
+       
+       public CompatScroller(Context context) {
+               if (VERSION.SDK_INT < VERSION_CODES.GINGERBREAD) {
+                       isPreGingerbread = true;
+                       scroller = new Scroller(context);
+                       
+               } else {
+                       isPreGingerbread = false;
+                       overScroller = new OverScroller(context);
+               }
+       }
+       
+       public void fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, int maxY) {
+               if (isPreGingerbread) {
+                       scroller.fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY);
+               } else {
+                       overScroller.fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY);
+               }
+       }
+       
+       public void forceFinished(boolean finished) {
+               if (isPreGingerbread) {
+                       scroller.forceFinished(finished);
+               } else {
+                       overScroller.forceFinished(finished);
+               }
+       }
+       
+       public boolean isFinished() {
+               if (isPreGingerbread) {
+                       return scroller.isFinished();
+               } else {
+                       return overScroller.isFinished();
+               }
+       }
+       
+       public boolean computeScrollOffset() {
+               if (isPreGingerbread) {
+                       return scroller.computeScrollOffset();
+               } else {
+                       overScroller.computeScrollOffset();
+                       return overScroller.computeScrollOffset();
+               }
+       }
+       
+       public int getCurrX() {
+               if (isPreGingerbread) {
+                       return scroller.getCurrX();
+               } else {
+                       return overScroller.getCurrX();
+               }
+       }
+       
+       public int getCurrY() {
+               if (isPreGingerbread) {
+                       return scroller.getCurrY();
+               } else {
+                       return overScroller.getCurrY();
+               }
+       }
+    }
+    
+    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
+       private void compatPostOnAnimation(Runnable runnable) {
+       if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {
+            postOnAnimation(runnable);
+            
+        } else {
+            postDelayed(runnable, 1000/60);
+        }
+    }
+    
+    private class ZoomVariables {
+       public float scale;
+       public float focusX;
+       public float focusY;
+       public ScaleType scaleType;
+       
+       public ZoomVariables(float scale, float focusX, float focusY, ScaleType scaleType) {
+               this.scale = scale;
+               this.focusX = focusX;
+               this.focusY = focusY;
+               this.scaleType = scaleType;
+       }
+    }
+    
+    private void printMatrixInfo() {
+       float[] n = new float[9];
+       matrix.getValues(n);
+       Log.d(DEBUG, "Scale: " + n[Matrix.MSCALE_X] + " TransX: " + n[Matrix.MTRANS_X] + " TransY: " + n[Matrix.MTRANS_Y]);
+    }
+}
\ No newline at end of file
index fc6dc21..769b98b 100644 (file)
@@ -1,6 +1,8 @@
-/* ownCloud Android client application
+/**
+ *   ownCloud Android client application
+ *
  *   Copyright (C) 2012  Bartek Przybylski
- *   Copyright (C) 2012-2013 ownCloud Inc.
+ *   Copyright (C) 2015 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,